2 番目の質問については、暗黙的に定義されていないことが原因である可能性があります。コンストラクターが単に暗黙的に宣言されている場合、エラーは発生しません。例:
struct A { A(int); };
struct B : A { };
// goes fine up to here
// not anymore: default constructor now is implicitly defined
// (because it's used)
B b;
最初の質問については、コンパイラが使用する名前によって異なります。標準が何を指定しているのかわかりませんが、(継承されたクラス名ではなく) 外部クラス名にアクセスできるため、たとえばこのコードは正しいです。
class A {};
class B: private virtual A {};
class C: public B { C(): ::A() { } }; // don't use B::A
たぶん、この時点で規格は十分に規定されていません。私たちは見なければならないでしょう。
コードに問題はないようです。さらに、コードが有効であるという表示があります。(仮想) 基本クラス サブオブジェクトはデフォルトで初期化されています。クラス名の名前検索が のスコープ内で行われることを意味するテキストはありませんC
。規格の内容は次のとおりです。
12.6.2/8
(C++0x)
特定の非静的データ メンバーまたは基本クラスが mem-initializer-id によって名前が付けられておらず (コンストラクターに ctor-initializer がないために mem-initializer-list がない場合を含む)、エンティティが仮想でない場合抽象クラスの基底クラス
[...]それ以外の場合、エンティティはデフォルトで初期化されます
また、C++03 にも同様のテキストがあります (あまり明確なテキストではありません。デフォルトのコンストラクターが 1 つの場所で呼び出され、別の場所ではクラスが POD であるかどうかに依存するようになっているだけです)。コンパイラがサブオブジェクトをデフォルトで初期化するには、デフォルトのコンストラクタを呼び出すだけで済みます。最初に基底クラスの名前を検索する必要はありません (どの基底が考慮されるかは 既にわかっています)。
確かに有効であることを意図しているこのコードを考えてみてください。ただし、これを行うと失敗します ( 12.6.2/4
C++0x を参照)。
struct A { };
struct B : virtual A { };
struct C : B, A { };
C c;
A
コンパイラのデフォルト コンストラクターが内のクラス名を単純にルックC
アップする場合、非仮想クラスA
と仮想クラスの両方A
のクラス名が検出されるため、どのサブオブジェクトを初期化するかに関してあいまいなルックアップ結果が得られます。あなたのコードが不正な形式であることを意図している場合、標準を明確にする必要があると思います.
12.4/6
コンストラクタについては、 のデストラクタについて次のように述べていることに注意してC
ください。
すべてのデストラクタは、修飾名で参照されているかのように呼び出されます。つまり、より派生したクラスで可能な仮想オーバーライド デストラクタは無視されます。
これは、次の 2 つの方法で解釈できます。
- A::~A() の呼び出し
- ::A::~A() の呼び出し
ここでは、標準があまり明確ではないように思えます。2 番目の方法では有効になります ( 3.4.3/6
C++0x によって、両方のクラス名A
がグローバル スコープで検索されるため)、最初の方法では無効になります (どちらもA
継承されたクラス名を見つけるため)。また、検索を開始するサブオブジェクトにも依存します (仮想基本クラスのサブオブジェクトを開始点として使用する必要があると思います)。このようになれば
virtual_base -> A::~A();
次に、仮想ベースのクラス名をパブリック名として直接見つけます。これは、派生クラスのスコープを調べて、アクセスできない名前を見つける必要がないためです。繰り返しますが、推論は似ています。検討:
struct A { };
struct B : A { };
struct C : B, A {
} c;
デストラクタが単純に を呼び出す場合、継承されたクラス名としてのthis->A::~A()
ルックアップ結果があいまいになるため、この呼び出しは有効ではありA
ません (スコープから直接基底クラス オブジェクトの非静的メンバー関数を参照することはできません。CC
を参照してください)。 10.1/3
++03)。関連するクラス名を一意に識別する必要があり、 のようなクラスのサブオブジェクト参照で開始する必要がありa_subobject->::A::~A();
ます。