VirtualとpImplの速度について

このQ&Aのポイント
  • VirtualとpImplのどちらを使用するか迷っています。まずはpImplパターンについて、コンパイル時間の短縮という宣伝がありますが、後者の方法でも同じことができます。
  • pImplパターンを使用するメリットは、ヘッダに変数を書かずにDLLを作成できることです。後者の方法ではヘッダを書き変えずにメンバ変数を変更することは可能ですが、pImplパターンを使うことでヘッダに一切の変数を書かずに済ますことができます。
  • 速度については、実験結果によりますが後者の方が有利です。ただし、DLLにすると状況が変わる可能性がありますので、まだ確認していない状況です。
回答を見る
  • ベストアンサー

VirtualとpImplの速度について

どちらの使用するか迷っています。ご助言をお願いします。 インターフェイスだけ晒して、メンバ変数を完全に見えないようにするためには、pImplパターンがあると思います。 //-------------------------------------------------------- //header.h class Imp; class TestPImpl {   Imp*pImpl; public:   TestPImpl();   void Func(); }; //cpp.cpp class Imp {   int i; public:   void Func()   {    i++;   } }; TestPImpl::TestPImpl() {  pImpl = new Imp; } void TestPImpl::Func() {  pImpl->Func(); } //-------------------------------------------------------- 一方、次のようにやることも可能です(呼び名は知りません)。 //-------------------------------------------------------- //header.h class VirtualBase { public:   virtual void Func() =0; }; VirtualBase*CreateVirtualBase(); //cpp.cpp class VirtualDeri : public VirtualBase {   int i; public:   void Func()   {    i++;   } }; VirtualBase*CreateVirtualBase() {   return new VirtualDeri; } //-------------------------------------------------------- このほうが、変数も見えず見た目のすっきりします。 さらに、速度を計測をしました。 //-------------------------------------------------------- //main.cpp int main() {   const int MAX_CNT = 10000000;   VirtualBase*v = CreateVirtualBase();   long startTime = timeGetTime();   for(int i=0;i<MAX_CNT;i++)    v->Func();   printf("Vertial:[%d]\n",timeGetTime() - startTime);   TestPImpl*p = new TestPImpl();   startTime = timeGetTime();   for(int i=0;i<MAX_CNT;i++)    p->Func();   printf("pImpl:[%d]\n",timeGetTime() - startTime); } 結果 >Virtual[336] >pImp[594] //-------------------------------------------------------- 後者の方が、速度的には有利です。(本来ならば、出力されたアセンブリなどを見て、勝手に"省略"されたかを確認する必要があるのかもしれませんが、現状自分はアセンブリを読むことはできません。) ここで質問です。よりシンプルに、かつ速度的にも有利に見える後者ではなく、pimplパターンを使うメリットは何なのでしょうか? 初めてpimplパターンを知ったときの宣伝は、コンパイル時間の短縮でした。しかし、後者の方法もヘッダを書き変えずにメンバ変数を変更することは可能なので、このメリットは後者の方法でも同じことです。 このような方法をとりたいと思っているのは、コンパイル時間を短縮するためではなく、現在作成しているDLLのヘッダに一切の変数を書きたくなかったからです。 DLLにすると、上記の実験の結果が変化するかはまだ確認していません。(DLLにすることにより状況が変わるかもしれないと考えています。) 質問内容自体にも間違い含まれているかもしれません。合わせてご助言お願いします。 環境はXP SP2 , VC8です。

  • qOat
  • お礼率80% (42/52)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

ひとつ挙げるなら、 pImplなら実装を"動的に差し替える"ことができます。

qOat
質問者

お礼

やはりそれぐらいですか。。。(それぐらいが大きいのかもしれませんが) 今回はpImplは封印することにしました。 返信ありがとうございます。

関連するQ&A

  • ヘッダのインクルード時のエラー

    初歩的な質問で恐縮です。 以下のようなファイルの構成でc++のプログラムを組んでいます。 <header.h> class H { public: virtual void func() = 0; }; <fileA.cpp> #include "header.h" class A : public H { public: void func() {} }; <fileB.cpp> #include "header.h" class B : public H { public: void func() {} }; <main.cpp> #include "fileA.cpp" #include "fileB.cpp" int main() { A a; B b; a.func(); b.func(); return 0; } これをビルドしようとすると、「クラス"H"を再定義しようとしています」とエラーが出てコンパイルができません。理屈は分かるのですが、これの対処方法が分かりません。この場合、header.hはJAVAにおけるInterfaceのような役割としてそれを使うfileA.cpp、fileB.cppの両者にインクルードしておきたいのです。これはどのようにして対処すべきなのでしょうか?

  • ラムダ式を関数に渡したいのですが

    Class1からClass2にある関数の引数にラムダ式で関数を渡すようなプログラムを作ろうと思い、以下のようにコードを記述しました。 #include <iostream> class Class1 { int i = 0; void func() { std::cout << "Hello world" << std::endl; } void init() { Class2 *class2 = new Class2(); class2->setFunc([this] { func(); i++; }()); } }; class Class2 { void(*mFunc)(); void runFunc(){ mFunc(); } public: void setFunc(void func()) { mFunc = func; } }; すると class2->setFunc([this] { func(); i++; }()); のところで「型"void"の引数は型"void(*)()"のパラメーターと互換性がありません」というエラーが発生してしまいます。 キャプチャにthisを渡したラムダ式を他のクラスの関数ポインタのような変数に代入させるようにしたいのですがどのように記述したらできますか

  • 変数の値がおかしくなる

    以下のようなプログラム(DLLとEXE)を書いたのですが、変数の値がおかしくなる(●参照)箇所があります。原因がお分かりになりましたら、ご回答をよろしくお願い致します。 ●mkdll.cppの、sub1()の(※1)までは、input[]が正しい値で入っているが、(※2)で値がおかしくなる。(※1)から(※2)までで、input[]は参照するだけです。 ---test.cpp(EXE)--- … main(){ int input[10],output[10]; int err; CDLL DLL; err = DLL.func(input,output); … return(0); } ---test.cpp End--- ---mkdll.h(DLL)--- … class __declspec(dllexport) CDLL{ public: int func(int *input, int *output); private: int sub1(int *input, int *output); int sub2(int in, int out); … }; ---mkdll.h End--- ---mkdll.cpp(DLL)--- #include "mkdll.h" … int CDLL::func(int *input, int*output){ int i; int error; error = sub1(input, output); return(error); } int CDLL::sub1(int *input, int *outout){ int i; int in1, in2, out1, out2; int err; //(※1) for(i=0; i<5; i++){ err = 0; in1 = input[i*2]; in2 = input[i*2+1]; //(※2) err = sub2(in1, out1); if(err != 0) return(err); … } } … ---mkdll.cpp End---

  • クラス内の関数内static変数について

    クラス内の「staticではないメンバ関数内で定義される」static変数の初期化タイミングはいつでしょうか? 自分としてはクラスのインスタンス生成時に初期化されるものだと思っていたのですが、どうもそうでは無さそうだという現象に出会ったもので。 例えば以下のようなサンプルプログラムがあるとします。 --------------------------------------- class TA { public: void func(int i); }; void TA::func(int i) { static int d=0; d += i; std::cout << d << std::endl; } int main() { for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); } } --------------------------------------- これを実行した時、自分としては 1 2 3 2 4 6 という結果を期待していた訳ですが、実際には 1 2 3 5 7 9 という結果になりました。 ということは、もしかしてメンバ変数ではなくともクラス内に現れるstatic変数はstaticなメンバ変数と同等ということなのでしょうか? 実際、上記ソースのforループ内にもう一つclass TAのインスタンスtbを追加してみると、 --------------------------------------- for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); TA tb; tb.func(i); tb.func(i); tb.func(i); } --------------------------------------- 1 2 3 4 5 6 8 10 12 14 16 18 となりました。 (まぁstaticではないメンバ変数に置き換えれば一応解決するのですが、個人的に何か凄く気持ち悪く感じて・・・)

  • C++ クラスをメンバにもつクラスについて

    お世話になります。C++初心者でうまくコードが書けません(><) クラス1と2があり、クラス1のメンバにはクラス2があります。 メインでクラス1をインスタンス化してクラス2のfunc2を呼び出します。 func2ではクラス1のインスタンスから呼び出された場合にクラス1の m_int1を取得します。 Class Class1{ public:  int m_int1;  Class2 m_Class2; }; Class Class2{ public: void func2(); }; void Class2::func2(){  /*ここの記述方法が分かりません*/  /*C1から呼び出されたらC1のm_int1に100を入れる*/  /*以下間違え*/  class1 C2_1;/*別のclass1のオブジェクトなのでこれに入れてもダメっぽい*/  C2_1.m_int1 = 100; } void main(){  class1 C1;  C1.m_int1 = 10;  C1.m_class2.func(); } C1.m_class2.func()の中から呼び出したC1にアクセスする方法が 分かりません(TT)。実体がまだあるのだからアクセスする方法は あると思うのですが・・・ どなたかよろしくお願いします。

  • extern記憶クラス指定子を使う事について

    prg1.cpp----------------------------- #include<stdio.h> void func(void); int gg=5678; int main(void) { printf("main gg=%d\n",gg); func(); return 0; } ---------------------------------- prg2.cpp-------------------------- #include<stdio.h> extern int gg; void func(void) { printf("func gg=%d\n",gg); } ---------------------------------- 以上「prg1.cpp」と「prg2.cpp」という名前のふたつのファイルを作成し、「prg1.cpp」で宣言したグローバル変数を「prg2.cpp」で利用可能にしたいと思っています。 それには、「prg1.cppをコンパイルし、prg2.cppもコンパイルして、両者のオブジェクト(コンパイル後のファイル)をリンクする」と参考書には書いてあったのですが、どのようにしたらリンクされるのかわかりません。 prg.1cpp---------------------- #include<stdio.h> void func(void); int gg=5678; int main(void) { printf("main gg=%d\n",gg); func(); return 0; } #include<stdio.h> extern int gg; void func(void) { printf("func gg=%d\n",gg); } ------------------------------- 以上のように、「prg1.cpp」のファイルに1つにまとめれば、なぜかよくわかりませんが実行できました。 しかし「prg1.cpp」と、「prg2.cpp」をリンクさせてみたいので、教えていただけると嬉しいです。

  • bccでエラー:メンバー関数は呼び出すかそのアドレスを~

    クラスのメンバ関数を、ある関数(実は qsort)の引数として渡したい と思っています。環境は OS:Windows XP コンパイラ:C++Builder6 に付属の bcc32.exe です。 下記のコード(t.cpp)をコマンドプロンプトで bcc32 t としてコンパイルすると「※1」の行で下のエラーになります。 「エラー E2235 t.cpp 29: メンバー関数は呼び出すか  そのアドレスをとらなければならない(関数 main() )」 どのように直せば良いでしょうか? -------------------------------------------------------- #include <stdio.h> #include <stdlib.h> class Aclass { public: void f(int); }; void Aclass::f(int x) { printf("classfunc %d\n", x); } void sub1(int x) { printf("sub-1 %d\n", x); } void call_func(void(*func)(int), int x) { func(2*x + 1); } void main(void) { call_func((void(*)(int))sub1, 11); Aclass *a = new Aclass; call_func((void(*)(int))a->f, -7); //※1 delete a; } -------------------------------------------------------- この掲示板、行頭の空白が削除されてしまいますねー。

  • C言語 動的確保とポインタ参照について

    以下のようなプログラムについて質問させて頂きます. main文で宣言されているaに配列を動的確保したいのですが,funcの関数内でaにアクセスする方法が分かりません.*(a[i])かな,とは思ったのですが上手く動作しませんでした. func実行後のmain文からはaの要素にアクセス出来るので,確保自体は成功していると思うのですが,如何でしょうか・・・? 宜しくお願いします. void func(int **a) {  *a = new int[32]; for(int cnt=0; cnt<32; cnt++) { /* aの配列の要素に値を代入したい(a[i] = i のように) */ } } int main(void) { int *a = NULL; func(&a); }

  • コンストラクタの順序?

    以下のソースに関して質問です。 /* library.h */ #pragma comment(lib, "library.lib") class A { public: A(); }; /* library.cpp */ #include "library.h" #include <list> class B { private: std::list<int> m_listi; public: void Func() { m_listi.push_back(0); //フリーズ return; } } g_CB; A::A() { g_CB.Func(); return; } /* test.cpp */ #include "library.h" A CA; int main() { return 0; } library.cppからlibrary.libをつくり、それをtest.cppで使用したところ、 ソースに示したところでプログラムがフリーズしてしまいます。 恐らくクラスBのm_listiが初期化される前にそれを使おうとしたためだと思います。 どうすればそれを避けられるでしょうか。。。

  • C言語の問題について

    下のプログラムにおいて実行結果は 02134 になります。 この02134になる過程は分かるのですが、時間がかかってしまいます。 iListとiGeneをいちいち紙に書き出さなければならないのでしょうか? 法則的なものが存在するとすれば、教えてください。 #include<stdio.h> #define MAX 5 void func(int *iGene); int main(void) { int i; int iGene[MAX]={0,1,0,0,0}; func(iGene); for(i=0;i<MAX;i++) { printf("%d",iGene[i]); } return (0); } void func(int *iGene) { int i,j; int iBuff; int iList[MAX]; for(i=0;i<MAX;i++) { iList[i]=i; } for(i=0;i<MAX;i++) { iBuff=iList[iGene[i]]; for(j=iGene[i]+1;j<MAX-i;j++) { iList[j-1]=iList[j]; } iGene[i]=iBuff; } } よろしくお願いします。

専門家に質問してみよう