8

これは未定義のメソッドを持つクラスです。コンパイラは、未定義のメンバー関数が呼び出されない限り、このクラスのインスタンスを構築できるようです:

struct A {
    void foo();
};

int main() {
    A a;      // <-- Works in both VC2013 and g++
    a.foo();  // <-- Error in both VC2013 and g++
}

これは似たような状況ですが、継承が関係しています。サブクラスBarは基本クラスを拡張しFooます。Fooメソッドを定義しますg()Bar同じ名前のメソッドを宣言しますが、定義しません:

#include <iostream>

struct Foo {
    void g() { std::cout << "g\n"; }
};

struct Bar : Foo {
    void g();
};

int main() {
    Bar b;      // Works in both VC2013 and g++
    b.Foo::g(); // Works in both VC2013 and g++
    b.g();      // Error in both VC2013 and g++
}

上記のバリエーションです。ここでの唯一の違いは、と の両方であるということg()です:virtualFooBar

#include <iostream>

struct Foo {
    virtual void g() { std::cout << "g\n"; }
};

struct Bar : Foo {
    virtual void g();
};

int main() {
    Bar b;      // Works in g++. But not in VC2013, which gives
                // 'fatal error LNK1120: 1 unresolved externals'

    b.Foo::g(); // Works in g++, but VC2013 already failed on b's construction
    b.g();      // Error in g++, but VC2013 already failed on b's construction
}

VC2013 と g++ の異なる動作の対比については、コード コメントを参照してください。

  1. もしあれば、どのコンパイラが正しいですか?
  2. VC2013 のコンパイラで、virtualキーワードを使用しないバージョンと比較して、キーワードを使用するバージョンでいくつかの異なる苦情があるのはなぜvirtualですか?
  3. 未使用の未定義メソッドは常に許可されますか? そうでない場合、それらが許可されないすべてのケースは何ですか?
  4. Barの宣言は、定義が提供されていないg()場合でもオーバーライドとしてカウントされますか?Bar
4

1 に答える 1

8

もしあれば、どのコンパイラが正しいですか?

どちらも正しいです。コードが間違っています。診断は必要ありません。[クラス.仮想]/11

クラスで宣言された仮想関数は、そのクラスで定義されるか、純粋な (10.4) として宣言されるか、またはその両方でなければなりません。ただし、診断は必要ありません (3.2)。

[intro.compliance]/2:

プログラムに診断が不要な規則違反が含まれる場合、この国際規格はそのプログラムに関する実装に要件を課しません。

GCC の最適化設定を確認してください。動作に影響を与える可能性があります。


未使用の未定義メソッドは常に許可されますか?

メンバー関数は、odr で使用される場合にのみ定義する必要があります。[basic.def.odr]/3:

すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。診断は必要ありません。

[basic.def.odr]/2 を考えてみましょう:

式は、未評価のオペランド (第 5 節) またはその部分式でない限り、評価される可能性があります。
[…]
純粋でない場合、仮想メンバー関数は ODR 使用されます。
名前が潜在的に評価される式または候補関数のセットのメンバーとして現れる非オーバーロード関数は、潜在的に評価される式から参照されたときにオーバーロード解決によって選択された場合、それが純粋な仮想関数でない限り、odr 使用されます。関数とその名前は明示的に修飾されていません。

decltypeor内で未定義の非仮想メンバー関数を使用することは引き続き許可されていますsizeof。しかし、非純粋な仮想関数は、単に純粋ではないという理由だけで ODR で使用されます。


Bar が定義を提供しない場合でも、Bar の g() の宣言はオーバーライドとしてカウントされますか?

はい。

于 2014-11-07T22:54:50.817 に答える