8

使用する用語が正確にはわかりませんが、ここに私の例を示します。

class Base {
public:
    virtual void test() = 0;
};

class Mixin {
public:
    virtual void test() { }
};

class Example : public Base, public Mixin {
};

int main(int argc, char** argv) {
    Example example;
    example.test();
    return 0;
}

Mixinクラスに純粋仮想関数を実装したいのですBase::testが、これをコンパイルすると、次のように表示されます。

test.cpp: In function ‘int main(int, char**)’:
test.cpp:15:13: error: cannot declare variable ‘example’ to be of abstract type ‘Example’
     Example example;
             ^
test.cpp:11:7: note:   because the following virtual functions are pure within ‘Example’:
 class Example : public Base, public Mixin {
       ^
test.cpp:3:18: note:    virtual void Base::test()
     virtual void test() = 0;
                  ^
test.cpp:16:13: error: request for member ‘test’ is ambiguous
     example.test();
             ^
test.cpp:8:18: note: candidates are: virtual void Mixin::test()
     virtual void test() { }
                  ^
test.cpp:3:18: note:                 virtual void Base::test()
     virtual void test() = 0;
                  ^

usingあいまいにならないようにステートメントを追加できます。

class Example : public Base, public Mixin {
public:
    using Mixin::test;
};

しかし、それは私がまだそれを実装していないと言っています:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:17:13: error: cannot declare variable ‘example’ to be of abstract type ‘Example’
     Example example;
             ^
test.cpp:11:7: note:   because the following virtual functions are pure within ‘Example’:
 class Example : public Base, public Mixin {
       ^
test.cpp:3:18: note:    virtual void Base::test()
     virtual void test() = 0;
                  ^

これを行うことは可能ですか?

1 つのオプションは からMixin継承することBaseですが、私の場合、いくつかの派生クラスがあり、それらは共通の祖先を共有していません。

4

2 に答える 2

8

クラスで、その基本クラス以外のメソッドを直接オーバーライドすることはできません。しかし、あなたは一種の回り道でそれを行うことができます. そのようなアプローチを 2 つ紹介します。

アプローチ1

これについては、Daniel Paul がthinkbottomup.com.auのC++ Mixins - Reuse through inheritance is good... when done the right wayというタイトルの投稿で説明しています。

あなたの場合、これは次のようになります。

class Base {
public:
    virtual void test() = 0;
};

template <typename T>
class Mixin : public T {
public:
    virtual void test() override { /*... do stuff ... */ }
};

class UnmixedExample : public Base {
    /* definitions specific to the Example class _not_including_
       a definition of the test() method */
};

using Example = class Mixin<UnmixedExample>;

int main(int argc, char** argv) {
    Example{}.test();
    return 0;
}

アプローチ 2: CRTP!

CRTPは「Curiously Recurring Template Pattern」です。これまでに見たことがない場合は、必ずそのリンクをたどってください。このアプローチでは、virtualあいまいさを避けるために継承指定子を使用します。また、前のアプローチとは異なり、MixinandExampleクラスの継承順序を逆にすることはありません。

class Base {
public:
    virtual void test() = 0;
};

template <typename T>
class Mixin : virtual T {
public:
    virtual void test() override { /*... do stuff ... */ }
};

class Example : public virtual Base, public virtual Mixin<Base> {
    /* definitions specific to the Example class _not_including_
       a definition of the test() method */
};

int main(int argc, char** argv) {
    Example{}.test();
    return 0;
}

両方のソリューションに関する注意:

  • CRTP があちこちで繰り返されているのが不思議ではありませんか? :-)
  • 私が使用したコードは、教育目的で C++11 ですが、C++98 でも同じことが機能します。
于 2017-04-27T21:32:36.843 に答える