我可以从不同的基类实现对同一函数的不同实现吗?
Can I implement different implementation to same function from different base classes?
假设如下:
class A{ virtual void f() = 0; };
class B{ virtual void f() = 0; };
我可以以某种方式执行以下操作吗?
class C : public A, public B
{
virtual void A::f(){ printf("f() from A"); }
virtual void B::f(){ printf("f() from B"); }
};
所以现在我可以做到了???
A* pa = new C();
pa->f(); // prints f() from A;
B* pb = (B*)pa;
pb->f(); // prints f() from B;
谢谢!!!
第一个解决方案
这个问题提醒了"立面"设计模式。这应该重写为:
class AC : public A
{ public: virtual void f(){ cout << "f() from A" << endl;}; };
class BC : public B ...
class C : public AC, public BC {};
其中 C 是"立面"。
所以在正确的调用语法应该是这样的:
C* c = new C();
c->AC::f();
c->BC::f();
如果你在AC和BC之间没有任何份额限制,这应该可以完成这项工作,因为它没有被关闭。
第二种解决方案
感谢 Casey(请参阅第一条评论),另一种解决方案是在模板中使用类 C 的前向声明,以允许调用定义后者的方法。
template <typename C>
class AC : public A {
public:
void f() { static_cast<C&>(*this).f_from_A(); }
};
template <typename C>
class BC : public B { ... };
因此,实现部分可以在同一类中完成。
class C : public AC<C>, public BC<C> {
public:
void f_from_A() { cout << "f_from_A" << endl; };
void f_from_B() ...
};
调用部分更干净,因为它不显示任何实现细节,并且最接近问题:
C* c = new C();
((A*) c) -> f();
((B*) c) -> f();
C 上不再有"默认"f(),并且有可能破坏预期的继承行为,并且更难阅读。
作为参考,以下链接似乎相关:
- 从不同的基类重载同名的虚函数。可能吗?
- C++同名的虚拟覆盖函数
- 派生类通过基类定义函数
第二个链接中的OP问他是否可以像你问的那样做一些事情:
class Impl : public A , public B
{
public:
void A::Function () { cout << "A::Function" << endl; }
void B::Function () { cout << "B::Function" << endl; }
};
约翰内斯的回答是:
不能在此处使用限定名称。我你写 void 函数() { ... }您正在覆盖这两个函数。赫伯·萨特展示了它是如何做到的 被解决。
另一种选择是重命名这些函数,因为显然它们 做一些不同的事情(否则我看不到问题 以相同的行为覆盖两者)。
所以一个可能的解决方案(来自第一个链接的James Kanze)看起来像这样:
class RemapA : public A
{
virtual void fnInA() = 0;
public:
virtual void fn()
{
fnInA();
}
};
class RemapB : public B
{
virtual int fnInB() = 0;
public:
virtual int fn()
{
return fnInB();
}
};
class C : public RemapA, public RemapB
{
virtual void fnInA() { /* ... */ }
virtual void fnInB() { /* ... */ }
// ...
};
赫伯·萨特(Herb Sutter)的链接基本上说了同样的事情。
要覆盖这两个函数,您需要中间类。C 中的 using 声明选择 A 的函数:
#include <iostream>
struct A{ virtual void f() = 0; };
struct B{ virtual void f() = 0; };
struct IntermediateA : public A {
virtual void f() override { std::cout << "An"; }
};
struct IntermediateB : public B {
virtual void f() override { std::cout << "Bn"; }
};
struct C : public IntermediateA, public IntermediateB
{
using IntermediateA::f;
};
int main() {
C c;
B* b = &c;
c.f();
b->f();
return 0;
}
是的。每个基类都有自己的虚拟表。
因此,通过强制转换,编译器将检查要转换为的类型的虚拟表,并获取指向该匹配函数的指针。
class A {public: virtual void f() = 0; };
class B {public: virtual void f() = 0; };
class C : public A, public B
{
public:
virtual void A::f(){ printf("f() from A"); }
virtual void B::f(){ printf("f() from B"); }
};
GCC 不支持此功能。只有Visual Studio这样做。
但是,您必须始终使用强制转换或作用域函数调用。
这将返回一个不明确的调用错误:
C* c = new C();
c->f(); //ambiguous call compilation error
This will work:
((B*)c)->f();
编译器显示的结构如下所示:(Visual studio flag: /d1reportSingleClassLayoutC)
class C size(8):
+---
| +--- (base class A)
0 | | {vfptr}
| +---
| +--- (base class B)
4 | | {vfptr}
| +---
+---
C::$vftable@A@:
| &C_meta
| 0
0 | &C::f
C::$vftable@B@:
| -4
0 | &CCCC::f
C::f this adjustor: 4
C::f this adjustor: 0
基本上,您可以看到匹配虚拟表的 2 个单独指针。
所以你可以做:
C* c= new C();
B* b = (B*)c;
b->f(); // calls C::B::f()
A* a = (A*)c;
a->f(); // calls C::A::f()
or even:
a = (A*)(C*)b;
a->f(); // calls C::A::f()
请注意,您需要将大小写b
回到派生类才能访问A
类型基类的虚拟表。
- 在命名空间内部还是外部实现 c++ 函数?
- 如何在C++中实现函数(f)(x)(y, z)(g)(r)
- 如何在C++中实现函数上的二叉搜索?
- 键按下事件错误 Qt 实现函数时
- 在子类之外实现函数导致未知错误
- 通过模板滥用实现函数式C++
- C++,实现函数"int next(std::string param)"时出现奇怪的编译器错误
- 我正在尝试创建自己的 strcat() 函数,而不是使用库实现函数<cstring>
- 如果未实现函数,则在链接时启用错误
- 用函数参数实现c++函数指针
- 如何在Android SDK中调用和实现C++函数
- 在 C++ RCPP 中实现 R 函数
- 实现函数模板填充多维对象
- 类的层次结构,试图在基本级别实现函数
- 用c++实现函数对象的自动检测类型
- 用shared_ptrs实现函数模板的C++实例化
- 在类中实现函数导致错误:成员引用基类型'ifstream (string)'不是结构或联合
- 用c++实现S函数.生成错误
- 引用可以用于实现函数重写吗
- 如何在c++中实现函数超时