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;
                  ^

是否有可能做到这一点?

我知道一种选择是Mixin从继承Base,但在我的情况下,有几个派生类,它们不共享一个共同的祖先。

4

2 回答 2

8

您不能直接让一个类覆盖不是其基类的方法。但是你可以用一种迂回的方式来做。我将介绍两种这样的方法——我更喜欢第二种。

方法一

Daniel Paul 在thinkbottomup.com.au上的一篇文章中对此进行了描述,题为C++ Mixins - Reuse through inheritance is good...当以正确的方式完成时

在您的情况下,这就是它的样子:

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继承说明符来避免歧义,并且与以前的方法不同 - 我们不会颠倒MixinExample类的继承顺序。

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 回答
4

你不能让一个类覆盖一个不相关的类的虚函数。你可以做不同的事情来解决这个问题。您可以使 mixin 成为(实际上)从 type 参数派生的模板并将其用作class Example : public virtual Base, Mixin,或者您可以在最终类中添加代码以调度到混合:

void Derived::test() { Mixin::test(); }
于 2013-10-22T21:09:33.530 回答