いつも大変お世話になっています。
VC++初心者です。
関数をクラス化していきたいのですが、具体的にどのようにしたら良いか
ご指導頂けませんでしょうか。
例えば、このようなソースがあった場合、どのようにクラス化させるのでしょうか。
(また、下記の例ですと、pulsとsubで1つのグループ、
goodMoringとgoodNightで1つのグループにさせる場合には
どうすれば宜しいでしょうか。)
//=======================
//Tool.hの中身
//=======================
int plus(int x, int y);
int sub(int x, int y);
void goodMorning();
void goodNight();
//=======================
//Tool.cppの中身
//=======================
#include <iostream.h>
int plus(int x, int y){
return x + y;
}
int sub(int x, int y){
return x - y;
}
void goodMorning(){
cout << "おはよう\n";
}
void goodNight(){
cout << "こんばんは\n";
}
//=======================
//Main.cppの中身
//=======================
#include <iostream.h>
#include "Tool.h"
int main(){
int a = puls(1,1);
cout << a <<'\n';
int b = puls(2,1);
cout << b <<'\n';
goodMorning();
goodNight();
}
No.7ベストアンサー
- 回答日時:
こんにちは。
FarEyesです。たびたびすみません。
#6の方法だと意図的に表示メッセージを切替えたい場合、わざわざシステム
の設定を変更しないといけないので、別な方法(開発者または使用者が好き
なときに切替えられる方法)を幾つか考えてみました。
※基本事項としてメイン側(クラス化した関数を呼ぶ側)のソースは変更しなく
ても済む方法です。
■方法1
表示するメッセージ文字列をリソースファイル(*.rc)上に記述しておいて、
クラス側でリソース上の文字列を取り出して表示する。
表示メッセージを切替える場合は、リソースファイル上の文字列の変更のみ
で対応可能。
※ただし、Windwos+VC++前提の話になります。
(他の処理系で可能かどうかは判りません)
※それと、メッセージを切替える場合はプログラムをリビルド(再生成)しな
おさないとできません。(プログラム実行時に動的には切替えられない)
以下はソース例です。
※該当部分のみ抜粋しています。
◎リソースID用のヘッダファイル:resource4.h
#define IDS_MSG1_STR1 1
#define IDS_MSG1_STR2 2
◎リソースファイル:MyRes4.rc
#include "resource4.h"
// String Table
STRINGTABLE DISCARDABLE
BEGIN
IDS_MSG1_STR1 "おはよう"
IDS_MSG1_STR2 "こんばんは"
END
※表示メッセージを替えたい場合はここの設定文字列を変更します。
注)変更した場合はプログラムの再生成(リビルド)が必要です。
◎クラスのヘッダソース:MyClass4.h
//======================================
//MyClass4.h:自作クラス用定義ヘッダ
//======================================
#ifndef _MYCLASS4_H__20091017_001__INCLUDE_
#define _MYCLASS4_H__20091017_001__INCLUDE_
//名前空間'MyClass'の指定
namespace MyClass {
//メッセージ出力クラスの定義
class CMsgOut {
public:
CMsgOut(){} //コンストラクタ
~CMsgOut(){} //デストラクタ
void goodMorning(void); //メッセージ出力1
void goodNight(void); //メッセージ出力2
};
}
#endif //#ifndef _MYCLASS4_H__20091017_001__INCLUDE_
◎クラスの本体ソース:MyClass4.cpp
//======================================
//MyClass4.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include <windows.h>
#include <winuser.h>
#include <winbase.h>
#include <tchar.h>
#include "resource4.h"
#include "MyClass4.h"
using namespace std;
using namespace MyClass;
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning(void)
{
//リソースからメッセージ文字列を取得(WindowsAPI使用)
int len;
_TCHAR szMsg[128];
len = ::LoadString( ::GetModuleHandle(NULL), IDS_MSG1_STR1,
szMsg, sizeof(szMsg) );
if( len<1 ){
//取得失敗時はエラーで戻る
cout << "String Load Error. (Resource_ID=IDS_MSG1_STR1)" << endl;
return;
}
//メッセージ出力
cout << szMsg << endl;
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight(void)
{
//リソースからメッセージ文字列を取得(WindowsAPI使用)
int len;
_TCHAR szMsg[128];
len = ::LoadString( ::GetModuleHandle(NULL), IDS_MSG1_STR2,
szMsg, sizeof(szMsg) );
if( len<1 ){
//取得失敗時はエラーで戻る
cout << "String Load Error. (Resource_ID=IDS_MSG1_STR2)" << endl;
return;
}
//メッセージ出力
cout << szMsg << endl;
}
■方法2
上記の方法1とやや似ていますが、表示するメッセージ文字列を iniファイル
などの外部の設定ファイルに記述しておいて、クラス側でその設定ファイル
上の文字列を読み込んで表示する。
表示メッセージを切替える場合は、設定ファイル上の文字列の変更のみ
で対応可能。
※こちらの方は、プログラムをリビルドしなくてもメッセージの切替えが可能
です。
以下はINIファイル及びソースの例です。
※但し、Windows+VC++前提です。
※一部抜粋しています。
◎INIファイル:Main5.ini
[Setting]
DispMsg1=おはよう
DispMsg2=こんばんは
※予め実行ファイルと同じフォルダに作成しておきます。
・下記ソースの場合はINIファイルがない場合は自動作成します。
(ただし、メッセージ文字列は既定の文字列になります。)
※表示メッセージを替えたい場合はここの設定文字列を変更します。
・変更した場合でもプログラムの再生成(リビルド)は必要ありません。
◎クラスのヘッダソース:MyClass5.h
//======================================
//MyClass5.h:自作クラス用定義ヘッダ
//======================================
#ifndef _MYCLASS5_H__20091017_001__INCLUDE_
#define _MYCLASS5_H__20091017_001__INCLUDE_
#include <tchar.h> //_TCHAR対応のためインクルード
//名前空間'MyClass'の指定
namespace MyClass {
//メッセージ出力クラスの定義
class CMsgOut {
public:
CMsgOut(){} //コンストラクタ
~CMsgOut(){} //デストラクタ
//メッセージ文字列の取得
int GetIniStr(int nMsgNo, _TCHAR *szMsg, int nMsgSize);
void goodMorning(void); //メッセージ出力1
void goodNight(void); //メッセージ出力2
};
}
#endif //#ifndef _MYCLASS5_H__20091017_001__INCLUDE_
◎クラスの本体ソース:MyClass5.cpp
//======================================
//MyClass5.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include <windows.h>
#include <winbase.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include "MyClass5.h"
using namespace std;
using namespace MyClass;
//メッセージ出力クラス:INIファイル上の文字列取得
int CMsgOut::GetIniStr(int nMsgNo, _TCHAR *szMsg, int nMsgSize)
{
_TCHAR szAppPath[_MAX_PATH]; //アプリケーションのフルパス名
_TCHAR szDrv[_MAX_DRIVE]; //ドライブ名
_TCHAR szDir[_MAX_DIR]; //フォルダ名
_TCHAR szFname[_MAX_FNAME]; //ファイル名(拡張子を除いたもの)
_TCHAR szExt[_MAX_EXT]; //拡張子
_TCHAR szIniFn[_MAX_PATH]; //INIファイルのフルパス名
DWORD dwLen; //文字列長
//引数の文字列バッファを初期化
szMsg[0] = '\0';
//アプリケーションのフルパス名を取得(WindowsAPI使用)
memset( szAppPath, 0, sizeof(szAppPath) );
dwLen = ::GetModuleFileName( NULL, szAppPath, sizeof(szAppPath) );
if( dwLen<1 ){
return 0; //取得失敗時はエラーで戻る
}
//フルパス名を構成要素に分割
_tsplitpath( szAppPath, szDrv, szDir, szFname, szExt );
//INIファイル名を作成
_tcscpy( szIniFn, szDrv );
_tcscat( szIniFn, szDir );
_tcscat( szIniFn, szFname );
_tcscat( szIniFn, _T(".ini") );
//INIファイル生成(なかった時のみ)(WindowsAPI使用)
::WritePrivateProfileString( _T(""), NULL, NULL, szIniFn );
//INIファイルからメッセージ文字列を取得(WindowsAPI使用)
switch( nMsgNo ){
case 1: //メッセージNo=1
//設定値の読込み
::GetPrivateProfileString( _T("Setting"), _T("DispMsg1"),
_T("Good Morning."), szMsg, nMsgSize, szIniFn );
//設定値の書込み(なかった時のため)
::WritePrivateProfileString( _T("Setting"), _T("DispMsg1"),
szMsg, szIniFn );
break;
case 2: //メッセージNo=2
//設定値の読込み
::GetPrivateProfileString( _T("Setting"), _T("DispMsg2"),
_T("Good Night."), szMsg, nMsgSize, szIniFn );
//設定値の書込み(なかった時のため)
::WritePrivateProfileString( _T("Setting"), _T("DispMsg2"),
szMsg, szIniFn );
break;
}
//取得した文字列の長さ(バイト数)を返す
return lstrlen( szMsg );
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning(void)
{
//INIファイルからメッセージ文字列を取得
int len;
_TCHAR szMsg[128];
len = GetIniStr( 1, szMsg, sizeof(szMsg) );
if( len<1 ){
//取得失敗時はエラーで戻る
cout << "String Read Error. (from INI file)" << endl;
return;
}
//メッセージ出力
cout << szMsg << endl;
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight(void)
{
//INIファイルからメッセージ文字列を取得
int len;
_TCHAR szMsg[128];
len = GetIniStr( 2, szMsg, sizeof(szMsg) );
if( len<1 ){
//取得失敗時はエラーで戻る
cout << "String Read Error. (from INI file)" << endl;
return;
}
//メッセージ出力
cout << szMsg << endl;
}
以上です。
ご回答、ありがとうございます。
また、大変長い間連絡せずにすみませんでした。
勝手ながら、本件は一度終了させて頂きたいと
思います。ご協力ありがとうございました。
No.6
- 回答日時:
こんにちは。
FarEyesです。念のため、#5で触れた「OS側で設定している地域情報」(コントロールパネルで
設定する地域情報)を取得して出力メッセージの自動切替えを行うバージョンを
作ってみました。
※ただし、Windows限定です。(WindowsAPIを使用しています)
メッセージ出力クラス(CMsgOut)側で、WindowsAPI(GetUserDefaultLCID)を
使用してシステムの地域情報(ロケールID)を取り出して、それを元に出力メッ
セージの切替えを行うようにしています。
※ただし、処理系などの環境の違いにより上手く動作しない可能性があります。
ですので、質問者さんご使用の環境でビルド可能および問題なく動作するか
どうかは判りません。
※また、これが質問者さんが意図しているものでなかった場合はすみません。
◎参考サイト
プログラミングの覚え書き
http://kwikwi.cocolog-nifty.com/blog/2007/05/ind …
ロケール ID (LCID) の一覧
http://msdn.microsoft.com/ja-jp/library/cc392381 …
■改造後ソース(出力メッセージの自動切替え対応)
注)インデントのため全角スペースを入れています。
◎ソース1(クラスのヘッダ)
//======================================
//MyClass3.h:自作クラス用定義ヘッダ
//======================================
#ifndef _MYCLASS3_H__20091016_001__INCLUDE_
#define _MYCLASS3_H__20091016_001__INCLUDE_
//名前空間'MyClass'の指定
namespace MyClass {
//ロケールID情報テーブルの構造体定義
typedef struct {
int nLCID; // ロケールID
int nDispLang; // 表示言語
// =1:日本語、=2:中国語、=3:英語
} T_LCID_INFO;
//ロケールID情報テーブル(外部参照定義)
extern const T_LCID_INFO tb_LCID_Info[];
//数値計算クラスの定義
class CNumCalc {
public:
CNumCalc(){} //コンストラクタ
~CNumCalc(){} //デストラクタ
int plus(int x, int y); //加算計算
int sub(int x, int y); //減算計算
};
//メッセージ出力クラスの定義
class CMsgOut {
public:
CMsgOut(){} //コンストラクタ
~CMsgOut(){} //デストラクタ
int GetDispLang(void); //ロケールID別の表示言語タイプ取得
void goodMorning(void); //メッセージ出力1
void goodNight(void); //メッセージ出力2
};
}
#endif //#ifndef _MYCLASS3_H__20091016_001__INCLUDE_
◎ソース2(クラスの本体)
//======================================
//MyClass3.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include <windows.h>
#include <winnls.h>
#include "MyClass3.h"
using namespace std;
using namespace MyClass;
/*==========================================================
<補足:ロケール情報(抜粋)>
ロケール名 言語コード 16進値 10進数
日本語 ja 0x0411 1041
中国語(中華人民共和国) zh-cn 0x0804 2052
中国語(香港) zh-hk 0x0C04 3076
中国語(シンガポール) zh-sg 0x1004 4100
中国語(台湾) zh-tw 0x0404 1028
英語(オーストラリア) en-au 0x0C09 3081
英語(ベリーズ) en-bz 0x2809 10249
英語(カナダ) en-ca 0x1009 4105
英語(アイルランド) en-ie 0x1809 6153
英語(ジャマイカ) en-jm 0x2009 8201
英語(ニュージーランド) en-nz 0x1409 5129
英語(南アフリカ) en-za 0x1C09 7177
英語(トリニダード) en-tt 0x2C09 11273
英語(U.K.) en-gb 0x0809 2057
英語(U.S.) en-us 0x0409 1033
==========================================================*/
//名前空間'MyClass'の指定
namespace MyClass {
//ロケールID情報テーブル
const T_LCID_INFO tb_LCID_Info[] = {
/* LCID, 表示タイプ */
{ 1041, 1 }, // 日本語
{ 2052, 2 }, // 中国語(中華人民共和国)
{ 3076, 2 }, // 中国語(香港)
{ 4100, 2 }, // 中国語(シンガポール)
{ 1028, 2 }, // 中国語(台湾)
{ 3081, 3 }, // 英語(オーストラリア)
{ 10249, 3 }, // 英語(ベリーズ)
{ 4105, 3 }, // 英語(カナダ)
{ 6153, 3 }, // 英語(アイルランド)
{ 8201, 3 }, // 英語(ジャマイカ)
{ 5129, 3 }, // 英語(ニュージーランド)
{ 7177, 3 }, // 英語(南アフリカ)
{ 11273, 3 }, // 英語(トリニダード)
{ 2057, 3 }, // 英語(U.K.)
{ 1033, 3 }, // 英語(U.S.)
{ -1, 0 } // テーブル終端コード
};
}
//数値計算クラス:加算計算
int CNumCalc::plus(int x, int y)
{
return x + y;
}
//数値計算クラス:減算計算
int CNumCalc::sub(int x, int y)
{
return x - y;
}
//ロケールID別の表示言語タイプ取得
int CMsgOut::GetDispLang(void)
{
//ロケールIDの取得
int nUsrLCID = ::GetUserDefaultLCID();
//ロケールIDから表示言語タイプを取得
int i;
int nDispLang = 0;
for(i=0; tb_LCID_Info[i].nLCID!=-1; i++){
if( nUsrLCID == tb_LCID_Info[i].nLCID ){
nDispLang = tb_LCID_Info[i].nDispLang;
break;
}
}
return nDispLang;
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning(void)
{
//ロケールIDから表示言語タイプ取得
int nDispLang = GetDispLang();
//表示言語タイプ別のメッセージ出力
switch( nDispLang )
{
case 1:
default:
cout << "おはよう" << endl;
break;
case 2:
cout << "早安" << endl;
break;
case 3:
cout << "good morning." << endl;
break;
}
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight(void)
{
//ロケールIDから表示言語タイプ取得
int nDispLang = GetDispLang();
//表示言語タイプ別のメッセージ出力
switch( nDispLang )
{
case 1:
default:
cout << "こんばんは" << endl;
break;
case 2:
cout << "晩安" << endl;
break;
case 3:
cout << "good night." << endl;
break;
}
}
◎ソース3(メインソース)
//======================================
//Main3.cpp:メインソース
//======================================
#include <iostream>
#include "MyClass3.h"
using namespace std;
int main()
{
int x, y;
int a, b;
//数値計算クラスのオブジェクト作成
MyClass::CNumCalc calc;
//MyClass::CNumCalc::plus()の実行
x=110; y=50;
a = calc.plus(x, y);
cout << "## Call=> MyClass::CNumCalc::plus()" << endl;
cout << x << "+" << y << "=" << a << endl;
//MyClass::CNumCalc::sub()の実行
x=980; y=30;
b = calc.sub(x, y);
cout << "## Call=> MyClass::CNumCalc::sub()" << endl;
cout << x << "-" << y << "=" << b << endl;
//メッセージ出力クラスのオブジェクト作成
MyClass::CMsgOut msg;
//MyClass::CMsgOut::goodMorning()の実行
cout << "## Call=> MyClass::CMsgOut::goodMorning()" << endl;
msg.goodMorning();
//MyClass::CMsgOut::goodNight()の実行
cout << "## Call=> MyClass::CMsgOut::goodNight()" << endl;
msg.goodNight();
return 0;
}
<上記サンプルの実行結果>
## Call=> MyClass::CNumCalc::plus()
110+50=160
## Call=> MyClass::CNumCalc::sub()
980-30=950
## Call=> MyClass::CMsgOut::goodMorning()
おはよう
## Call=> MyClass::CMsgOut::goodNight()
こんばんは
以上です。
No.5
- 回答日時:
こんにちは。
FarEyesです。> ■#3の補足の(2)について
> 私の説明が足りませんでした。
> Main2C.cpp:メインソースを一切変えずに(引数を使わずに)
> 表現できないのかな、と思い質問させて頂きました。
> 実際にそれは可能なのでしょうか。
すみませんが補足願います。
それは、OS側で設定している表示言語(コントロールパネルの地域の設定など)
を取得して、自動的にクラス側で表示メッセージを切替えるということでしょうか?
No.4
- 回答日時:
こんにちは。
#2、#3です。■#3の補足の(1)について
> (1)
> namespaceは、.hファイル、.cppファイルの両方に記述する必要があるのでしょうか。
こういう場合は、実際に試してみるのが一番手っ取り早いです。
.cpp側ソース(#3の場合、MyClass2.cpp)から、
"namespace MyClass {" と対応する "}" を
コメントアウトするか削除して、コンパイルしてみれば解ると思います。
当方の環境で検証してみました。【※検証ソース(その1)使用】
すると下記のように何れもコンパイルエラーとなりました。
◎Microsoft Visual C++ Ver 5.0でコンパイルした結果
MyClass2A.cpp(12) : error C2653: 'CNumCalc' : 識別子がクラス名でも名前空間名でもありません。
MyClass2A.cpp(18) : error C2653: 'CNumCalc' : 識別子がクラス名でも名前空間名でもありません。
MyClass2A.cpp(24) : error C2653: 'CMsgOut' : 識別子がクラス名でも名前空間名でもありません。
MyClass2A.cpp(30) : error C2653: 'CMsgOut' : 識別子がクラス名でも名前空間名でもありません。
◎Borland C++ 5.5でコンパイルした結果
エラー E2090 MyClass2A.cpp 12: 型限定子 'CNumCalc' がクラス名または名前空間名ではない
エラー E2040 MyClass2A.cpp 12: 宣言が正しく終了していない
*** 2 errors in Compile ***
◎cygwin上のgcc(g++)でコンパイルした結果
MyClass2A.cpp:12: error: `CNumCalc' has not been declared
MyClass2A.cpp:18: error: `CNumCalc' has not been declared
MyClass2A.cpp:24: error: `CMsgOut' has not been declared
MyClass2A.cpp:30: error: `CMsgOut' has not been declared
◎検証ソース(その1)
//======================================
//MyClass2A.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include "MyClass2.h" //自作クラス用のヘッダ
using namespace std; //←暗黙の名前空間名をstdとする
//名前空間'MyClass'の指定
//namespace MyClass { //←コメントアウトで無効化
//数値計算クラス:加算計算
int CNumCalc::plus(int x, int y)
{
return x + y;
}
//数値計算クラス:減算計算
int CNumCalc::sub(int x, int y)
{
return x - y;
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning()
{
cout << "「おはよう」" << endl;
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight()
{
cout << "「こんばんは」" << endl;
}
//} //←コメントアウトで無効化
以上のように、やはり.cpp側でも名前空間の指定が必要なようです。
※ただし処理系によって違うかもしれません。
ちなみに下記ソース【検証ソース(その2)】のように記述した場合はエラー
にはなりませんでした。
using namespace MyClass;
を追加することで MyClass も暗黙に参照される名前空間としてコンパイラ
に指示しています。
また、
using namespace std;
も記述していますので、std と MyClass の両方が暗黙参照の名前空間と
なります。
この場合、コンパイラの動作としては、
CNumCalc::~~ と CMsgOut::~~ の関数は、
→std 内では見つからなかったが、MyClass 内では見つかった。
cout と endl は、
→std 内で見つかった。
ということで問題なくコンパイルされた。ということだと思われます。
◎検証ソース(その2)
//======================================
//MyClass2B.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include "MyClass2.h" //自作クラス用のヘッダ
using namespace std; //←暗黙の名前空間名をstdとする
using namespace MyClass; //←'MyClass'も暗黙に参照する名前空間に加える
//数値計算クラス:加算計算
int CNumCalc::plus(int x, int y) //←名前空間MyClassを参照
{
return x + y;
}
//数値計算クラス:減算計算
int CNumCalc::sub(int x, int y) //←名前空間MyClassを参照
{
return x - y;
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning() //←名前空間MyClassを参照
{
cout << "「おはよう」" << endl; //←名前空間stdを参照
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight() //←名前空間MyClassを参照
{
cout << "「こんばんは」" << endl; //←名前空間stdを参照
}
■#3の補足の(2)について
> (2)
> おそらくインターフェイスの考え方だと思うのですが、
> void CMsgOut::goodMorning()、 void CMsgOut::goodNight()を
> 中国語用に
> void CMsgOut::goodMorning()
> {
> cout << "「早安」" << endl;
> }
>
> //メッセージ出力クラス:メッセージ出力2
> void CMsgOut::goodNight()
> {
> cout << "「晩安」" << endl;
> }
> に切り替えるには、どのようにすれば宜しいでしょうか。
見当違いでしたらすみません。
この場合、一例ですが、関数に「出力メッセージの言語を指定する引数」
を設けて、関数を呼ぶ側で指定するようにすれば良いかと思います。
※以下は、その改造後のソースです。
■改造後ソース(出力メッセージの切替え対応)
注)インデントのため全角スペースを入れています。
◎ソース1(クラスのヘッダ)
//======================================
//MyClass2C.h:自作クラス用定義ヘッダ
//======================================
#ifndef _MYCLASS2C_H__20091012_001__INCLUDE_ //←多重インクルード防止用
#define _MYCLASS2C_H__20091012_001__INCLUDE_ // の定義
//名前空間'MyClass'の指定
namespace MyClass {
//数値計算クラスの定義
class CNumCalc {
public:
CNumCalc(){} //コンストラクタ
~CNumCalc(){} //デストラクタ
int plus(int x, int y); //メンバ関数:加算計算
int sub(int x, int y); //メンバ関数:減算計算
};
//メッセージ出力クラスの定義
class CMsgOut {
public:
CMsgOut(){} //コンストラクタ
~CMsgOut(){} //デストラクタ
void goodMorning(int nLang = 0); //メンバ関数:メッセージ出力1
//引数 nLang のデフォルト値を0とする
//※引数省略時は nLang=0 となる
void goodNight(int nLang = 0); //メンバ関数:メッセージ出力2
//引数 nLang のデフォルト値を0とする
//※引数省略時は nLang=0 となる
};
}
#endif //#ifndef _MYCLASS2C_H__20091012_001__INCLUDE_
◎ソース2(クラスの本体)
//======================================
//MyClass2C.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include "MyClass2C.h" //自作クラス用のヘッダ
using namespace std; //←暗黙の名前空間名をstdとする
using namespace MyClass; //←'MyClass'も暗黙に参照する名前空間に加える
//数値計算クラス:加算計算
int CNumCalc::plus(int x, int y)
{
return x + y;
}
//数値計算クラス:減算計算
int CNumCalc::sub(int x, int y)
{
return x - y;
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning(int nLang /*=0*/)
{
if(nLang==0){
cout << "「おはよう」" << endl;
}else{
cout << "「早安」" << endl;
}
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight(int nLang /*=0*/)
{
if(nLang==0){
cout << "「こんばんは」" << endl;
}else{
cout << "「晩安」" << endl;
}
}
◎ソース3(メインソース)
//======================================
//Main2C.cpp:メインソース
//======================================
#include <iostream>
#include "MyClass2C.h" //自作クラス用のヘッダ
using namespace std; //←暗黙の名前空間名をstdとする
int main()
{
int x, y;
int a, b;
//数値計算クラスのオブジェクト作成
MyClass::CNumCalc calc;
//MyClass::CNumCalc::plus()の実行
x=123; y=45;
a = calc.plus(x, y);
cout << "## MyClass::CNumCalc::plus()の実行" << endl;
cout << x << "+" << y << "=" << a << endl;
//MyClass::CNumCalc::sub()の実行
x=987; y=65;
b = calc.sub(x, y);
cout << "## MyClass::CNumCalc::sub()の実行" << endl;
cout << x << "-" << y << "=" << b << endl;
//メッセージ出力クラスのオブジェクト作成
MyClass::CMsgOut msg;
cout << "## MyClass::CMsgOut内の関数実行(1回目,引数=0)" << endl;
//MyClass::CMsgOut::goodMorning()の実行(1回目)
msg.goodMorning(0);
//MyClass::CMsgOut::goodNight()の実行(1回目)
msg.goodNight(0);
cout << "## MyClass::CMsgOut内の関数実行(2回目,引数=1)" << endl;
//MyClass::CMsgOut::goodMorning()の実行(2回目)
msg.goodMorning(1);
//MyClass::CMsgOut::goodNight()の実行(2回目)
msg.goodNight(1);
cout << "## MyClass::CMsgOut内の関数実行(3回目,引数省略)" << endl;
//MyClass::CMsgOut::goodMorning()の実行(3回目)
msg.goodMorning();
//MyClass::CMsgOut::goodNight()の実行(3回目)
msg.goodNight();
return 0;
}
<上記サンプルの実行結果>
## MyClass::CNumCalc::plus()の実行
123+45=168
## MyClass::CNumCalc::sub()の実行
987-65=922
## MyClass::CMsgOut内の関数実行(1回目,引数=0)
「おはよう」
「こんばんは」
## MyClass::CMsgOut内の関数実行(2回目,引数=1)
「早安」
「晩安」
## MyClass::CMsgOut内の関数実行(3回目,引数省略)
「おはよう」
「こんばんは」
以上です。
この回答への補足
ご回答、ありがとうございます。
■#3の補足の(1)について
ご指摘頂いて、納得しました。
namespaceを、.h内で設定して
using namespaceで、.cpp内で.hで設定したnamespaceを
使用しているのですね!
■#3の補足の(2)について
私の説明が足りませんでした。
Main2C.cpp:メインソースを一切変えずに(引数を使わずに)
表現できないのかな、と思い質問させて頂きました。
実際にそれは可能なのでしょうか。
No.3
- 回答日時:
こんにちは。
#2です。私も厳密なC++の言語仕様等にはあまり詳しくないので、以下の記述は間違って
いるかもしれません。その際はすみません。
namespace(名前空間)はクラスとはまた別の概念なので、#2で述べた親クラス、
サブクラスの関係(クラスの階層構造、クラスの継承など)の話しとはまた別の話し
になります。
※誤解を招くような言い回しになってしまい、すみませんでした。
namaspace とは、関数名などの識別子の使用可能範囲(スコープ)を限定する
目的で使用されます。
これによって、同じ名前の関数などが複数あった場合でも、namespaceを使用
することで名前の衝突を防ぐことができます。
また、using namespace std; の記述ですが、これは std という名前空間名を
デフォルトのものとして、名前空間名を省略した場合に暗黙的に std が使用され
るように定義するものです。
C++の標準ライブラリ内の識別子(cin、cout、endl など)は std という名前空間
の中に定義されていて、本来なら、
std::cin、std::cout、std::endl
などと記述すべきところですが数箇所にある場合、そのつど std:: を付加するの
も煩わしいため、それを簡略化する目的で使用されます。
■#2のソースに namespace を使用した例
2つのクラス(CNumCalc、CMsgOut)を名前空間 MyClass 内のクラスとして定義
しています。
注)インデントのため全角スペースを入れています。
ソースとして使用する際は半角スペースorタブに置換して下さい。
◎ソース1
//======================================
//MyClass2.h:自作クラス用定義ヘッダ
//======================================
#ifndef _MYCLASS_H__20091012_001__INCLUDE_ //←多重インクルード防止用
#define _MYCLASS_H__20091012_001__INCLUDE_ // の定義
//名前空間'MyClass'の指定
namespace MyClass {
//数値計算クラスの定義
class CNumCalc {
public:
CNumCalc(){} //コンストラクタ
~CNumCalc(){} //デストラクタ
int plus(int x, int y); //メンバ関数:加算計算
int sub(int x, int y); //メンバ関数:減算計算
};
//メッセージ出力クラスの定義
class CMsgOut {
public:
CMsgOut(){} //コンストラクタ
~CMsgOut(){} //デストラクタ
void goodMorning(); //メンバ関数:メッセージ出力1
void goodNight(); //メンバ関数:メッセージ出力2
};
}
#endif //#ifndef _MYCLASS_H__20091012_001__INCLUDE_
◎ソース2
//======================================
//MyClass2.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include "MyClass2.h" //自作クラス用のヘッダ
using namespace std; //←暗黙の名前空間名をstdとする
//名前空間'MyClass'の指定
namespace MyClass {
//数値計算クラス:加算計算
int CNumCalc::plus(int x, int y)
{
return x + y;
}
//数値計算クラス:減算計算
int CNumCalc::sub(int x, int y)
{
return x - y;
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning()
{
cout << "「おはよう」" << endl;
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight()
{
cout << "「こんばんは」" << endl;
}
}
◎ソース3
//======================================
//Main2A.cpp:メインソース
//======================================
#include <iostream>
#include "MyClass2.h" //自作クラス用のヘッダ
using namespace std; //←暗黙の名前空間名をstdとする
int main()
{
int x, y;
int a, b;
//数値計算クラスのオブジェクト作成
// CNumCalc calc; //←これだとエラー
MyClass::CNumCalc calc; //←名前空間指定
//数値計算クラスのメンバ関数[plus]の実行
x=100; y=50;
a = calc.plus(x, y);
cout << x << "+" << y << "=" << a << endl;
//↑これは std::cout としたのと同じ
//数値計算クラスのメンバ関数[sub]の実行
x=200; y=120;
b = calc.sub(x, y);
std::cout << x << "-" << y << "=" << b << std::endl;
//↑明示的に名前空間を指定した場合
//メッセージ出力クラスのオブジェクト作成(名前空間指定)
// CMsgOut msg; //←これだとエラー
MyClass::CMsgOut msg; //←名前空間指定
//メッセージ出力クラスのメンバ関数[goodMorning]の実行
msg.goodMorning();
//メッセージ出力クラスのメンバ関数[goodNight]の実行
msg.goodNight();
return 0;
}
<上記サンプルの実行結果>
100+50=150
200-120=80
「おはよう」
「こんばんは」
以上です。
この回答への補足
ご回答、ありがとうございます。
おそらく、これが私がやりたかったことです。
サンプルソースのご提示、ありがとうございます。
すみませんが、更に2点伺えませんでしょうか。
(1)
namespaceは、.hファイル、.cppファイルの両方に記述する必要があるのでしょうか。
(2)
おそらくインターフェイスの考え方だと思うのですが、
void CMsgOut::goodMorning()、 void CMsgOut::goodNight()を
中国語用に
void CMsgOut::goodMorning()
{
cout << "「早安」" << endl;
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight()
{
cout << "「晩安」" << endl;
}
に切り替えるには、どのようにすれば宜しいでしょうか。
No.2
- 回答日時:
こんにちは。
ものは試しで、クラス化してみるのも良いかと思います。
実際にやってみないと実感できないこともありますので。。。
参考までに、ご提示の関数をクラス化してみました。
※下記は、あくまで一例です。
他にもやり方はあると思いますので、色々試してみて下さい。
見当外れの内容でしたらすみません。
plus と sub で1つのクラス(数値計算クラス:CNumCalc)、
goodMoring と goodNight で1つのクラス(メッセージ出力クラス:CMsgOut)
というように、2つの別々のクラスとして作成してあります。
#1さんへの補足にあるように、クラスの中のサブクラスというイメージの作り
ではないので、ご希望のものとは違うかもしれません。
■サンプルソース
注)インデントのため全角スペースを入れています。
ソースとして使用する際は半角スペースorタブに置換して下さい。
◎ソース1
//======================================
//MyClass.h:自作クラス用定義ヘッダ
//======================================
#ifndef _MYCLASS_H__20091012_001__INCLUDE_ //←多重インクルード防止用
#define _MYCLASS_H__20091012_001__INCLUDE_ // の定義
//数値計算クラスの定義
class CNumCalc {
public:
CNumCalc(){} //コンストラクタ
~CNumCalc(){} //デストラクタ
int plus(int x, int y); //メンバ関数:加算計算
int sub(int x, int y); //メンバ関数:減算計算
};
//メッセージ出力クラスの定義
class CMsgOut {
public:
CMsgOut(){} //コンストラクタ
~CMsgOut(){} //デストラクタ
void goodMorning(); //メンバ関数:メッセージ出力1
void goodNight(); //メンバ関数:メッセージ出力2
};
#endif //#ifndef _MYCLASS_H__20091012_001__INCLUDE_
◎ソース2
//======================================
//MyClass.cpp:自作クラスのメンバ関数
//======================================
#include <iostream>
#include "MyClass.h" //自作クラス用のヘッダ
using namespace std;
//数値計算クラス:加算計算
int CNumCalc::plus(int x, int y)
{
return x + y;
}
//数値計算クラス:減算計算
int CNumCalc::sub(int x, int y)
{
return x - y;
}
//メッセージ出力クラス:メッセージ出力1
void CMsgOut::goodMorning()
{
cout << "おはよう" << endl;
}
//メッセージ出力クラス:メッセージ出力2
void CMsgOut::goodNight()
{
cout << "こんばんは" << endl;
}
◎ソース3
//======================================
//Main2.cpp:メインソース
//======================================
#include <iostream>
#include "MyClass.h" //自作クラス用のヘッダ
using namespace std;
int main()
{
//数値計算クラスのオブジェクト作成
CNumCalc calc;
//数値計算クラスのメンバ関数[plus]の実行
int a = calc.plus(1,1);
cout << "1+1=" << a << endl;
//数値計算クラスのメンバ関数[sub]の実行
int b = calc.sub(2,1);
cout << "2-1=" << b << endl;
//メッセージ出力クラスのオブジェクト作成
CMsgOut msg;
//メッセージ出力クラスのメンバ関数[goodMorning]の実行
msg.goodMorning();
//メッセージ出力クラスのメンバ関数[goodNight]の実行
msg.goodNight();
return 0;
}
<サンプルの実行結果>
1+1=2
2-1=1
おはよう
こんばんは
以上です。参考になれば幸いです。
この回答への補足
ご回答、ありがとうございます。
具体的にソースを提示して頂いてとても分かりやすいです。
ありがとうございます。
#1さんの「この回答への補足」でも書きましたが、#2さんの
提示していただいたその2つのクラスを更にもう1つ大きなグループ
にくくれないでしょうか。
おそらく、それがnamespaceだと思うのですが、それがうまく
使えていません。また、#2さんの提示されたソースの
using namespace std;
はどのような役割を果たしているのでしょうか。
No.1
- 回答日時:
お疲れ様です。
ごめんなさい、もしかしたら貴方は根本的な考え方を間違っているのではないのではと思ってしまいました。
関数をグループ化する為にクラスがあるのではありません。
データとそのデータを操作するための関数を一体化させるためにクラスというものがあります。
以上
この回答への補足
ご回答、ありがとうございます。
ご指摘頂いたとおり、私は、クラス化やオブジェクト指向プログラミングを
理解していない為、具体的なコーディングを見てみたい思い、
今回質問させて頂きました。
私が伝えたい「グループ化させたい」という意図が正確に伝えられずに
すみません。
例えば、.net(C++/CLIの場合)でMessageBoxを使用するとき、
System::Windows::Forms::MessageBox::Show("メッセージ","タイトル");
と書くと思います。
このようなイメージで、計算系をkeisanグループとして
int plus(int x, int y);
int sub(int x, int y);
のメンバ関数を割り当てて、
出力系をshutsuryokuグループとして
void goodMorning();
void goodNight();
のメンバ関数を割り当てたいのです。
よって、これを使用する場合は、
xxx::shutsuryoku::goodMorning();
のようなイメージで使いたいのです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
10進数からN進数に変換するプロ...
-
VisualStudioでC++クラスを追加...
-
C言語について。
-
どうして+3
-
プログラム言語について c言語...
-
C++でデスクトップGUIアプリ開...
-
int16_t の _t は何?
-
2つほどお聞きしたいことがあり...
-
gccを行ってもexeファイルが生...
-
VisualStudio2022でC言語プログ...
-
C言語って古いですか?
-
ストリームについて。
-
QT(C++)の学習方法について
-
Cのコンパイルでコメントアウト...
-
C言語について。
-
Windows Formアプリからコンソ...
-
パソコン
-
今ってプログラミング言語は何...
-
プログラミング言語についてc++...
-
次の記述について
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
FriendとPublicの違い。。。
-
既定のコンストラクタがない?
-
(UWSC) 「#32770」の意味わかり...
-
クラスのアドレスを引数として...
-
ダイアログ表示時にチェックボ...
-
エディットコントロールでEnter...
-
イベントにAddHandlerされてい...
-
【ASP.NET】 独自で作成したク...
-
DebugクラスとTraceクラスの違い
-
MFCのCListCtrlでスクロールを検出
-
C++ protectedにアクセス不可
-
C++で継承元のクラスの代入演算...
-
継承したクラスを、継承元のク...
-
OnInitDialog()の関数の組み込み方
-
ダイアログクラスのコントロー...
-
MessageBoxを継承したい
-
DataGridViewのセルに斜線を引...
-
このコンパイルエラーの意味に...
-
MFCアプリのコマンドラインでパ...
-
C#のクラス設計について教えて...
おすすめ情報