- ベストアンサー
【C++】関数からクラスに変更する方法
- 関数をクラス化する方法を教えてください。
- "Tool.h"と"Tool.cpp"にある関数をクラスにまとめる方法を教えてください。
- "Main.cpp"でクラスのメンバー関数を呼び出す方法を教えてください。
- みんなの回答 (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; } 以上です。
その他の回答 (6)
こんにちは。FarEyesです。 念のため、#5で触れた「OS側で設定している地域情報」(コントロールパネルで 設定する地域情報)を取得して出力メッセージの自動切替えを行うバージョンを 作ってみました。 ※ただし、Windows限定です。(WindowsAPIを使用しています) メッセージ出力クラス(CMsgOut)側で、WindowsAPI(GetUserDefaultLCID)を 使用してシステムの地域情報(ロケールID)を取り出して、それを元に出力メッ セージの切替えを行うようにしています。 ※ただし、処理系などの環境の違いにより上手く動作しない可能性があります。 ですので、質問者さんご使用の環境でビルド可能および問題なく動作するか どうかは判りません。 ※また、これが質問者さんが意図しているものでなかった場合はすみません。 ◎参考サイト プログラミングの覚え書き http://kwikwi.cocolog-nifty.com/blog/2007/05/index.html ロケール ID (LCID) の一覧 http://msdn.microsoft.com/ja-jp/library/cc392381.aspx ■改造後ソース(出力メッセージの自動切替え対応) 注)インデントのため全角スペースを入れています。 ◎ソース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() こんばんは 以上です。
こんにちは。FarEyesです。 > ■#3の補足の(2)について > 私の説明が足りませんでした。 > Main2C.cpp:メインソースを一切変えずに(引数を使わずに) > 表現できないのかな、と思い質問させて頂きました。 > 実際にそれは可能なのでしょうか。 すみませんが補足願います。 それは、OS側で設定している表示言語(コントロールパネルの地域の設定など) を取得して、自動的にクラス側で表示メッセージを切替えるということでしょうか?
こんにちは。#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:メインソースを一切変えずに(引数を使わずに) 表現できないのかな、と思い質問させて頂きました。 実際にそれは可能なのでしょうか。
こんにちは。#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; } に切り替えるには、どのようにすれば宜しいでしょうか。
こんにちは。 ものは試しで、クラス化してみるのも良いかと思います。 実際にやってみないと実感できないこともありますので。。。 参考までに、ご提示の関数をクラス化してみました。 ※下記は、あくまで一例です。 他にもやり方はあると思いますので、色々試してみて下さい。 見当外れの内容でしたらすみません。 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; はどのような役割を果たしているのでしょうか。
- toda hiro(@hiro_knigh)
- ベストアンサー率39% (59/151)
お疲れ様です。 ごめんなさい、もしかしたら貴方は根本的な考え方を間違っているのではないのではと思ってしまいました。 関数をグループ化する為にクラスがあるのではありません。 データとそのデータを操作するための関数を一体化させるためにクラスというものがあります。 以上
補足
ご回答、ありがとうございます。 ご指摘頂いたとおり、私は、クラス化やオブジェクト指向プログラミングを 理解していない為、具体的なコーディングを見てみたい思い、 今回質問させて頂きました。 私が伝えたい「グループ化させたい」という意図が正確に伝えられずに すみません。 例えば、.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(); のようなイメージで使いたいのです。
お礼
ご回答、ありがとうございます。 また、大変長い間連絡せずにすみませんでした。 勝手ながら、本件は一度終了させて頂きたいと 思います。ご協力ありがとうございました。