6

まず、stackoverflow ( thisthis、およびthis one ) に既に同様の質問があることを知っているため、問題の理由を理解しています。残念ながら、それは私がそれを解決するのに役立ちません。

上記の質問はすべてデフォルトのパラメーターなしのコンストラクターに関するものですが、デフォルト値を持つ 2 つのパラメーター コンストラクターを使用しているときに問題が発生しました。オブジェクトの代わりに関数宣言。

これが私のコードの一部です(クラス名は長くて関連性がないため、名前を変更しました):

class algoContainer{
public:
algoContainer(algo1Virtual &alg1 = algo1Concrete::emptyInstance(),
      algo2Virtual &alg2 = algo2Concrete::instance());

someUsefulFunction();
};

class algo1Concrete : public algo1Virtual{
    private:
    algo1Concrete();
    public:
    static algo1Concrete &emptyInstance(); // "empty" instance treated
                                           // specifically
                                           //  -- uses private no arg constructor
    algo1Concrete(const std::vector<data> &myData); // construcotr
};

class algo1Virtual{
    // ... all functions virtual, no implementations ...
};


// ... similar for algo2Virtual/Concrete ...

クラス内のすべての関数は実装されていますが、Concreteクラス内の関数はどれも実装されていませんVirtual(コンストラクタとデストラクタを除く)。

だから、今私の問題は、次のようなことをしたいということです:

std::vector <data> workData;
// fill workData
algoContainer myAC(algo1Concrete(workData));
myAC.someUsefulFunction(); // this line gives compile error

素敵でキュートでエレガントですが、機能しません (リンクしたすべての質問と同じエラー)。問題を最も厄介な parseと呼んでいるこのフォーラムチュートリアルを見つけましたが、それは解決策です (引数を括弧で囲みます) は問題を解決しません (その場合、エラーメッセージの長い束ですが、編集できますそれが役立つ場合は後で質問します-それらはすべて仮想関数の継承に関連しています)。

デフォルトのすべてのパラメーターでコンストラクターを使用する場合、および最初のパラメーターを個別に構築する場合でも、コードをテストしました。

std::vector <data> workData;
// fill workData
algo1Concrete myA1(workData);
algoContainer myAC(myA1);

myAC.someUsefulFunction(); // now it works fine

algoContainer myAC2;
myAC2.someUsefulFunction(); // this also works

コードをそのまま使用できますが、現在使用しているものよりもエレガントなソリューションを誰かが提供してくれれば幸いです。


編集:最も厄介な解析を修正したときに表示されるエラーメッセージ

括弧付きのコードを使用する場合:

algoContainer myAC((algo1Concrete(workData)));

私のエラーは次のとおりです。

/some_path/main.cpp:47:65: error: no matching function for call to ‘algoContainer::algoContainer(algo1Concrete)’
/some_path/main.cpp:47:65: note: candidates are:
/some_path/algo/algocont.h:45:5: note: algoContainer::algoContainer(algo1Virtual&, algo2Virtual&)
/some_path/algo/algocont.h:45:5: note:   no known conversion for argument 1 from ‘algo1Concrete’ to ‘algo1Virtual&’
/some_path/algo/algocont.h:36:7: note: algoContainer::algoContainer(const algoContainer&)
/some_path/algo/algocont.h:36:7: note:   no known conversion for argument 1 from ‘algo1Concrete’ to ‘const algoContainer&’

読みやすくするために、パスの名前を変更し、サンプル ファイルとクラス名 (上記と同じ) を挿入しました。備考:line 45は、問題のコンストラクターの定義です。一方、line 36ラインclass algoContainerです。

私もこのコードで試しました:

algoContainer myDect((algo1Virtual)(algo1Concrete(workData)));

そして、エラーは完全に異なります:

/some_path/main.cpp:47:86: error: cannot allocate an object of abstract type ‘algo1Virtual’
/some_path/algo/alg1/algo1virtual.h:31:7: note:   because the following virtual functions are pure within ‘algo1Virtual’:
/some_path/algo/alg1/algo1virtual.h:42:8: note:     virtual algo1Virtual::~algo1Virtual()
/some_path/algo/alg1/algo1virtual.h:39:18: note:    virtual void algo1Virtual::someAlgo1Function(std::vector<data>&)
/some_path/main.cpp:47:87: error: no matching function for call to ‘algoContainer::algoContainer(algo1Virtual)’
/some_path/main.cpp:47:87: note: candidates are:
/some_path/algo/algocont.h:45:5: note: algoContainer::algoContiner(algo1Virtual&, algo2Virtual&)
/some_path/algo/algocont.h:45:5: note:   no known conversion for argument 1 from ‘algo1Virtual’ to ‘algo1Virtual&’
/some_path/algo/algocont.h:36:7: note: algo1Virtual::algo1Virtual(const algo1Virtual&)
/some_path/algo/algocont.h:36:7: note:   no known conversion for argument 1 from ‘algo1Virtual’ to ‘const algo1Virtual&’

お役に立てれば。

4

4 に答える 4

3

algoContainer myAC(algo1Concrete(workData));

この行は違法です。右辺値を変更可能な左辺値参照にバインドすることはできません。それはそうでなければなりませんconst- たとえそうであったとしても、オブジェクトはコンストラクター以外の関数で使用される前に死んでしまいます。

于 2012-03-19T14:52:06.883 に答える
3

この問題は、コンストラクターが取る引数が原因のようです:

algoContainer( algo1Virtual &alg1,
               algo2Virtual &alg2 );

注: 簡潔にするために、デフォルトの引数を削除しました。

これは、引数を非 const 参照として受け取ります。したがって、次のような呼び出しを行うと:

algoContainer myAC(algo1Concrete(workData));

の構築:

algo1Concrete(workData)

匿名の一時的な構築につながります。匿名の一時変数は非 const 参照にバインドできません。これらは一時的なものであり、変更を加えるとすぐに消えてしまうためです (これは本当の理由ではありませんが、意味があるようです。匿名変数を変更しても意味がありません)。後で使用する方法がないため(名前なし)、または最終的に(一時的)一時的に使用できます)。実際には、非 const 参照は左辺値にのみバインドでき、匿名の一時変数は右辺値です。(詳細:非 const 参照は左辺値にのみバインドできます)

一般に、この種の使用は、構築されるオブジェクトの完全な所有権を関数に与えたいことを意味します。これは、値渡し (高価) か、C++11 では右辺値参照による受け渡しによって行うことができます。

値渡しは次のようになります。

algoContainer( algo1Virtual alg1,
               algo2Virtual alg2 );

これにより、不要なコピーが発生します。

もう 1 つのオプションは、次のように C++11 で右辺値参照によって渡すことです。

algoContainer( algo1Virtual &&alg1,
               algo2Virtual &&alg2 );

これで、最初の使用法は箱から出してすぐに動作します:

std::vector <data> workData;
// fill workData
algoContainer myAC(algo1Concrete(workData));
myAC.someUsefulFunction();

ただし、オブジェクトがコンストラクターに「移動」され、 algoContainer がデータの所有権を取得するように、2 番目の使用法を変更する必要があります (names ローカル変数は「不適切」であり、まったく使用しないでください。

std::vector <data> workData;
// fill workData
algo1Concrete myA1(workData);
algoContainer myAC(std::move(myA1)); //NOTICE THE std::move call.
//myA1 is now a dummy, and unusable as all the internals have gone.
myAC.someUsefulFunction(); 

上記の例を機能させるには、次のシグネチャを使用して algo1Concrete の移動コンストラクターを実装する必要があります。

algo1Concrete ( algo1Concrete&& other )

これは単に内部を現在の状態に転送し、「その他」を未定義の状態のままにします。(詳細: http://msdn.microsoft.com/en-us/library/dd293665.aspx )

注: デフォルトの引数について。

関数へのデフォルトの引数は、利便性よりも混乱を招くため、通常は避けることをお勧めします。すべてのデフォルト パラメータは、関数をオーバーロードするだけで「シミュレート」できます。したがって、あなたの場合、3 つの ctor があります。

algoContainer(); //This assumes that the args were both the statics
algoContainer( algo1Virtual alg1 ); //This assumes that arg2 was the static.
algoContainer( algo1Virtual alg1, algo2Virtual alg2 ); //This uses both input.

より冗長であり、現在継承コンストラクターを実装しているコンパイラーは多くないため、コードをコピーすることもよくあります。ただし、これにより、問題の調査中にポップアップする多くのデバッグ/マジック バリューの問題から 1 つが分離されます。しかし、FWIW、それは単なる意見です。

于 2012-03-20T15:13:47.107 に答える
0

これを書いてください:

algoContainer myAC((algo1Concrete(workData)));

次に、インターネットで「最も厄介な解析」を検索します。StackOverflowにもこの質問の重複が何百もありますが、質問自体で問題が特定されることはないため、見つけるのは困難です。(もしそうなら、疑問の余地はありません。)


(編集後:)一時オブジェクト(値で返される関数呼び出しによって作成されたオブジェクトなど)は、非定数参照にバインドされません。あなたは言う必要があります:

algo1Concrete ac = algo1Concrete(workData);
algoContainer myAC(ac);
于 2012-03-19T14:45:31.293 に答える
0

現在のソリューションの代替として、追加の括弧のペアを使用するか、コピーの初期化を使用できます。

于 2012-03-19T14:48:42.947 に答える