使用多重继承来满足抽象基类
Use multiple inheritance to satisfy abstract base class
为什么这不起作用?继承的函数签名是否微妙地不正确,或者是抽象基类强制"之前"的成员函数被继承或它是别的什么?在没有函数包装器的情况下,这能被说服工作吗?
#include <iostream>
struct AbsBase {
virtual void foo() = 0;
virtual void bar() = 0;
};
struct ProvideFoo {
void foo() { std::cout << "foon"; }
};
struct ProvideBar {
void bar() { std::cout << "barn"; }
};
struct Concrete : public ProvideFoo, public ProvideBar, public AbsBase {
// I guess I could put function wrappers here... sigh...
//void bar() {ProvideBar::bar();}
//void foo() {ProvideFoo::foo();}
};
int main() {
Concrete c;
c.foo();
c.bar();
}
为什么你的代码编译失败
我认为反对者对你有点苛刻,因为你通过单独的类提供两个纯虚函数的实现的理由有一些直观的吸引力。
唉,你同时在做两件不相关的事情。ProvideFoo
和ProvideBar
与AbsBase
抽象类完全无关。你也可以从AbsBase
中继承它们,但是它们中的每一个仍然是一个抽象类。在任何一种情况下,当前的Concrete
都是一个抽象类,因为它派生自至少一个具有纯虚函数的类。你不能从这样的类中创建对象。
修改代码,第一部分
最简单的方法是从AbsBase
中删除子类,直接从ProvideFoo
和ProvideBar
中删除子类。当然,现在在Concrete
中没有virtual
函数,因此进一步的子类化不能轻易地覆盖foo
和bar
功能。
#include <iostream>
struct ProvideFoo {
void foo() { std::cout << "foon"; }
};
struct ProvideBar {
void bar() { std::cout << "barn"; }
};
struct Concrete : public ProvideFoo, public ProvideBar {};
int main() {
Concrete c;
c.foo();
c.bar();
}
实例1
修复你的代码,第二部分
你也可以创建多个接口和多个具体的实现,像这样:
#include <iostream>
struct AbsFoo {
virtual void foo() = 0;
};
struct AbsBar {
virtual void bar() = 0;
};
struct ProvideFoo: AbsFoo {
void foo() { std::cout << "foon"; }
};
struct ProvideBar: AbsBar {
void bar() { std::cout << "barn"; }
};
struct Concrete : public ProvideFoo, public ProvideBar {};
int main() {
Concrete c;
c.foo();
c.bar();
}
示例二
修复你的代码,第三部分
现在为encore:您也可以使用virtual
继承时,ProvideFoo
和ProvideBar
的子类从AbsBase
使用virtual
关键字
#include <iostream>
struct AbsBase {
virtual void foo() = 0;
virtual void bar() = 0;
};
struct ProvideFoo: virtual AbsBase {
void foo() { std::cout << "foon"; }
};
struct ProvideBar: virtual AbsBase {
void bar() { std::cout << "barn"; }
};
struct Concrete : public ProvideFoo, public ProvideBar {};
int main() {
Concrete c;
c.foo();
c.bar();
}
这是非常高级的c++,如果您的类还包含成员数据,则会变得非常复杂。对于你的代码,我更愿意使用第二种解决方案。
实例三
我在问题中没有说清楚,但我确实想知道为什么代码不能编译。TemplateRex给出了一个很棒的答案。
也就是说,这里解释了为什么代码不能编译,但也没有抱怨成员名有歧义。首先,这里有一些类似的东西可以编译。
struct A {
virtual void foo() { std::cout << "A::foo()n"; };
};
struct B {
void foo() { std::cout << "B::foo()n"; }
};
struct C : public A, public B {};
int main() {
// This is fine.
C c;
// Uncommenting the next line would cause an ambiguous member name lookup and
// invalidate the program.
//c.foo();
}
幸运的是,我们的程序不一定是病态的,因为可能会发生不明确的名称查找。如果确实发生了不明确的名称查找,则程序是不正确的。10.2.7
通过添加更多的foo()定义,可以用不加注释的c.foo()创建一个有效的程序。
// Name lookup never proceeds to the base classes if it succeeds locally. 10.2.4
struct C : public A, public B {
void foo() { std::cout << "C::foo()n"; }
};
通过使A::foo()成为纯虚函数来将A更改为抽象类,可以防止编译。
struct A {
virtual void foo() = 0;
};
struct B {
void foo() { std::cout << "C::foo()n"; }
};
struct C : public A, public B {};
int main() {
// This is illegal.
C c;
// The next line is irrelevant.
//c.foo();
}
编译器错误表明struct C是抽象的。为什么?让我们从抽象类到底意味着什么开始。
10.4抽象类 抽象类是只能作为其他类的基类使用的类;抽象类的对象只能作为派生类的子对象创建。如果一个类至少有一个纯虚函数,那么它就是抽象的。"显然C至少有一个纯虚函数,因此是一个抽象类,我们只能从它继承。在了解为什么C语言有纯虚函数之前,我们已经可以回答部分问题了。C是一个抽象类,我们试图创建一个实例,这是非法的。简单地创建对象是非法的。如果你从不尝试访问纯虚函数,那也没关系。
那么为什么C语言有纯虚函数呢?必须是A::foo()。B::foo()发生了什么?A::foo()以某种方式优先吗?
首先,我们通常说派生类"有"它们继承的函数,但这模糊了真正发生的事情。
"10.1.4[…对于在最派生类的类格中出现的每个不同的非虚基类,最派生对象(1.8)应包含该类型的对应的不同基类子对象。[…]"
这里很清楚派生类和基类是不同的。我们不仅仅继承了一堆函数。现在,重写成员与访问多个同名成员之间的区别已经很明显了。可以继承具有相同名称和签名的多个函数。如果注意作用域,甚至可以引用单独的函数,但不明确的名称查找是非法的。
若要不是抽象类,继承的纯虚函数必须被覆盖。我们确实继承了一个没有被重写的纯虚函数,因此我们有一个抽象类。顺便说一下,我们还继承了一个具有相同签名的非纯虚函数,但这只是无关紧要的琐事。
- 如何定义一个纯抽象基类
- 将抽象基类中的所有纯虚函数定义为 varaidaic 模板
- 在C++单元测试上下文中,抽象基类是否应将其他抽象基类作为函数参数
- 有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
- 自定义异常中的用户定义的空构造函数,具有多个继承和抽象基类
- 如何保存指向抽象基类的指针/引用,但在 c++ 中仍然可以复制
- C++:在共享对象中调用抽象基类构造函数/未定义的符号
- 从抽象基类中获取重载函数
- 如何构建一个 Map,其中键是抽象基类(而不是值)
- 无法调用纯抽象基类超载
- 私下继承C++抽象基类是什么意思
- 如何在抽象基类中实现运算符+
- 如何为抽象基类创建模板实例化?
- 崩溃 __cxxabiv1::__cxa_pure_virtual () - vtable ptr 到抽象基类
- CRTP - 是否可以创建一个抽象基类?
- 嵌套抽象基类的泛型模板
- 抽象基类的派生类未正确覆盖基纯虚拟方法
- 在C 中的数组中存储抽象基类的不同派生类的对象
- "Has a" C++关系,最佳做法是让一个类"implement"多个抽象基类?
- C++ 重新定义抽象基类