当我尝试编译以下代码时:
class A {
public:
A(int v) : virt(v) { }
int virt;
int getVirt(void) const { return virt; }
};
class B : private virtual A {
protected:
B(int v) : A(v) { }
using A::getVirt;
};
class C : public B, private virtual A {
protected:
C(int v) : A(v), B(v) { }
using A::getVirt;
};
class D : public C {
public:
D(void) : C(3) { }
using C::getVirt;
};
#include <iostream>
int main(int argc, char *argv[]) {
D d;
std::cout << "The number is: " << d.getVirt() << std::endl;
return 0;
}
我收到关于D没有实例化A的错误;那是对的吗?如果在层次结构中嵌入了虚拟基础,那么所有派生类还需要虚拟地从该基础派生,以便它们可以调用虚拟基础的参数构造函数吗?
BTW,这是G ++产生的错误:
Main.cpp: In constructor ‘D::D()’:
Main.cpp:22:18: error: no matching function for call to ‘A::A()’
Main.cpp:22:18: note: candidates are:
Main.cpp:3:5: note: A::A(int)
Main.cpp:3:5: note: candidate expects 1 argument, 0 provided
Main.cpp:1:7: note: A::A(const A&)
Main.cpp:1:7: note: candidate expects 1 argument, 0 provided
答案 0 :(得分:6)
这与访问控制无关(至少不是主要)。相反,您必须了解虚拟基础的工作原理:虚拟基础子对象由最多派生的类初始化。由于您未在A
的构造函数初始值设定项列表中提及D
,因此尝试使用默认构造函数,但不存在。
要解决此问题,请在A
D
D() : A(3), C(3) { }
当您说A(3)
时,根据12.6.2 / 2执行名称查找:
在 mem-initializer-id 中,在构造函数的类的范围内查找初始的非限定标识符,如果在该范围内找不到,则在包含构造函数的范围中查找它。定义
正如Drew Dorman正确指出的那样,您可以通过调用::A
来强制直接指向虚拟基类,从而获得所需的访问权限。
答案 1 :(得分:1)
正如Kerrek SB所提到的,您需要在A
的构造函数中初始化D
。
但是,您还必须使用范围运算符明确告诉编译器您不从其(私有)派生上下文访问A
。
class D : public C {
public:
D(void) : ::A(3), C(3) { }
// ^^ Access this constructor from a global context
using C::getVirt;
};
这也意味着您的构造函数必须是公共的,就像您的代码一样。