11

他の 2 つのクラス ('TestA' と 'TestB') から派生したクラス ('TestC') があります。どちらも同じ署名を持つ仮想関数を持っています。

「TestC」を介して関数にアクセスできるようにするには、使用するバージョンを指定する必要があります。「TestC」で関数を明示的に上書きし、必要なバージョンを呼び出すと、これは機能します。

#include <iostream>

class TestA
{
public:
    virtual void test() {std::cout<<"a";}
};

class TestB
{
public:
    virtual void test() {std::cout<<"b";}
};

class TestC
    : public TestA,public TestB
{
public:
    void test() {TestB::test();}
};

int main(int argc,char *argv[])
{
    TestC c;
    TestA *a = static_cast<TestA*>(&c);
    a->test();
    c.test();
    for(;;);
    return EXIT_SUCCESS;
}

出力: "bb"

それが期待される結果です。ただし、関数を明示的に上書きする代わりに「using」キーワードを使用すると、予期しない動作が発生することに気付きました。

class TestC
    : public TestA,public TestB
{
public:
    using TestB::test;
};

(他は同じです)

出力: "ab"

誰かが私にこれを説明できますか?「テスト」が突然仮想ではなくなったように見えますか? 関数を明示的に上書きせずにこれを行う方法はありますか? (「オーバーライドを使用する」のようなもの)

4

2 に答える 2

10

ではusing、 を定義しませんが、それが表示TestC::test()されていることを伝えTestB::test()ます (したがって、あいまいにならないように非表示にします) TestA::test()c.test()

于 2016-06-03T09:57:49.513 に答える
4

using 宣言が仮想関数をオーバーライドすることはありません。ただし、多重継承を明確にすることはできます。例では、次をa->test()呼び出します。

  1. TestC のオーバーライド (TestB::f を呼び出す)
  2. TestB のオーバーライド (TestC にはオーバーライドがありません)

次の (菱形の) 仮想継承の using 宣言は、必要な最終的なオーバーライドを提供しません。

struct Base {
    virtual void f();
};
struct A : virtual Base {
    virtual void f() override {}
};
struct B : virtual Base {
    virtual void f() override {}
};

struct Derived : A, B {
    // error: no unique final overrider for ‘virtual void Base::f()’ in ‘Derived’
    using A::f;
};

その他の例:

#include <iostream>

// Single Inheritance
// ==================

namespace Single {

struct A {
    virtual void f() { std::cout<<"A\n"; }
};
struct AA : A {
    virtual void f() override { std::cout<<"AA\n"; }
};

struct Derived : AA {
    // Has no impact if not called explicitly
    using A::f;
};

} // namspace


// Multiple Inheritance
// ====================

namespace Multiple {

struct A {
    virtual void f() { std::cout<<"A\n"; }
};
struct AA : A {
    virtual void f() override { std::cout<<"AA\n"; }
};
struct B {
    virtual void f() { std::cout<<"B\n"; }
};
struct BB : B {
    virtual void f() override { std::cout<<"BB\n"; }
};
struct Derived : AA, BB {
    // Disambiguate A::f (AA::f) and B::f (BB::f)
    using A::f;
};

} // namspace


// Test
// ====

int main() {
    std::cout << "Single\n";
    {
        Single::Derived d;
        d.f();          // calls AA::f
        d.Derived::f(); // calls A::f because of the using-declaration
    }

    std::cout << "Multiple\n";
    {
        Multiple::Derived d;
        d.f();          // calls AA::f
        d.Derived::f(); // calls A::f because of the using-declaration
    }
}

注: ドラフト標準 N4296 には、決定的な説明は見つかりませんでした。

于 2016-06-03T21:05:26.940 に答える