此代码无法编译:
#include <iostream>
class BaseV1 {
public:
BaseV1(int i = 0) {
std::cout << i;
}
void foo() {}
};
class DataV1 : public BaseV1 {
public:
DataV1() : BaseV1(1) {}
};
class BaseV2 : public BaseV1 {};
class DataV2 : public DataV1, public BaseV2 {};
int main() {
DataV2().foo(); // request for member ‘foo’ is ambiguous
return 0;
}
所以我读到了钻石问题,我想出了我认为是这个解决方案,它使一个完整的路径(DataV2 : BaseV2 : BaseV1
)虚拟。然而,这并没有改变任何事情;
#include <iostream>
class BaseV1 {
public:
BaseV1(int i = 0) {
std::cout << i;
}
void foo() {}
};
class DataV1 : public BaseV1 {
public:
DataV1() : BaseV1(1) {}
};
class BaseV2 : virtual public BaseV1 {};
class DataV2 : public DataV1, virtual public BaseV2 {};
int main() {
DataV2().foo(); // request for member ‘foo’ is ambiguous
return 0;
}
我通过使另一个路径(DataV2 : DataV1 : BaseV1
)虚拟化来编译示例,这不是我真正想要的,因为我不喜欢过多地接触现有的代码库(V1
):
#include <iostream>
class BaseV1 {
public:
BaseV1(int i = 0) {
std::cout << i;
}
void foo() {}
};
class DataV1 : virtual public BaseV1 { // I do not want to make this virtual, I think.
public:
DataV1() : BaseV1(1) {}
};
class BaseV2 : virtual public BaseV1 {};
class DataV2 : virtual public DataV1, public BaseV2 {
public:
DataV2() : DataV1() {}
};
int main() {
DataV1().foo(); // this prints 1, as expected
DataV2().foo(); // this prints 0, not 1 - so DataV1's constructor is skipped
return 0;
}
即使代码能够编译,它在运行时也会失败,因为似乎跳过了DataV1
的构造函数。
所以我的问题是如何避免这里的菱形问题,理想情况下不涉及V1
继承路径?
1条答案
按热度按时间5gfr0r5j1#
virtual
并不能神奇地解决所有问题。BaseV1
的virtual
继承使得派生最多的类直接从BaseV1
继承。但这意味着DataV2
仍然有两个BaseV1
类-一个直接继承自BaseV1
,另一个在DataV1
内部。可能的解决方案:
DataV1
也具有虚拟继承(显然)DataV2
不继承DataV1
。DataV2
提供自己的void foo()
方法,该方法委托给特定的内部实现(例如:void foo() {DataV1::foo();}
)