コンストラクタ初期化リストの{}初期化は、抽象型への参照を初期化するときの()初期化とどのように異なりますか?以下のクラスバーをご覧ください。
class AbstractBase
{
public:
AbstractBase() {}
virtual ~AbstractBase() = default;
virtual void ab() = 0;
};
class Foo : public AbstractBase
{
public:
Foo() {}
void ab() {}
};
class Bar
{
public:
Bar(const AbstractBase& base) : myBase{base} {}
private:
const AbstractBase& myBase;
};
int main()
{
Foo f{};
Bar b{f};
}
コンパイルするとエラーが発生します
test5.cpp: In constructor ‘Bar::Bar(const AbstractBase&)’:
test5.cpp:22:48: error: cannot allocate an object of abstract type ‘AbstractBase’
Bar(const AbstractBase& base) : myBase{base}
^
test5.cpp:2:7: note: because the following virtual functions are pure within ‘AbstractBase’:
class AbstractBase
^
test5.cpp:8:18: note: virtual void AbstractBase::ab()
virtual void ab() = 0;
行を変更する
Bar(const AbstractBase& base) : myBase(base) {}
コンパイルして正常に実行されます。
StroustrupのC ++ 11の本を読んで、std :: initializer_list <>をとるコンストラクターと他のコンストラクターとの間にあいまいさがあった場合を除いて、ほとんどすべての場合で{}は()と同じであるという印象を受けました。タイプとしてautoを使用している場合、どちらもここでは実行していません。
簡単な答え:これはC ++ 14で修正された標準のバグであり、g ++ 4.9で修正されています(C ++ 11モードにも遡及的に適用されます)。欠陥レポート1288
より簡単な例を次に示します。
struct S
{
int x;
S() { } // this causes S to not be an aggregate (otherwise aggregate
// initialization is used instead of list initialization)
};
S x = 5;
S const &y { x } ;
x = 6;
std::cout << y << std::endl; // output : 5
C ++ 11のテキストでは、の意味は;S const &y {x};
にバインドy
しないことx
です。実際の意味は、一時的なものを作成し、それに参照をバインドすることです。C ++ 11 [dcl.init.ref] / 3から:
それ以外の場合、Tが参照型の場合、Tによって参照される型の一時的なprvalueがリストで初期化され、参照はその一時的なものにバインドされます。[注:参照型が非const型への左辺値参照である場合、通常どおり、バインディングは失敗し、プログラムは不正な形式になります。—エンドノート]
これはかなりばかげています。明らかに、このコードの目的はにy
直接バインドすることx
です。C ++ 14では、テキストが変更されました。
それ以外の場合、初期化子リストにタイプEの単一要素があり、Tが参照型ではないか、その参照型がEに参照関連している場合、オブジェクトまたは参照はその要素から初期化されます。
型はそれ自体(またはその基本クラスの1つ)に参照関連しているため、ここのサンプルと実際のコードでは、実際に正しくバインドする必要があります。
エラーメッセージは、C ++ 11の文言に従いbase
、参照をバインドするための一時的なfromを作成しようとしているコンパイラから送信されます。base
は抽象型であるため、これは失敗します。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加