C++ 虚拟继承和静态继承——在C++;
如果你有这样的东西:C++ 虚拟继承和静态继承——在C++;,c++,oop,inheritance,C++,Oop,Inheritance,如果你有这样的东西: #include <iostream> template<typename T> class A { public: void func() { T::func(); } }; class B : public A<B> { public: virtual void func() { std::cout << "into func"; } };
#include <iostream>
template<typename T> class A
{
public:
void func()
{
T::func();
}
};
class B : public A<B>
{
public:
virtual void func()
{
std::cout << "into func";
}
};
class C : public B
{
};
int main()
{
C c;
c.func();
return 0;
}
#包括
模板类别A
{
公众:
void func()
{
T::func();
}
};
B类:公共A
{
公众:
虚空函数()
{
标准::cout
您如何实现类A,使得如果B有一个虚拟覆盖,它是动态调度的,而如果B没有,它是静态调度的
有些矛盾,不是吗?类A的用户可能对B或C一无所知。如果您有对A的引用,那么知道func()
是否需要动态调度的唯一方法就是查看vtable。因为A::func()
不是虚拟的,它没有条目,因此没有地方放置信息。一旦你将其虚拟化,你就可以查看vtable,它是动态调度的
获取直接函数调用(或内联线)的唯一方法是使用非虚函数,并且不通过基类指针进行间接寻址
<>编辑:我认为Scala中的这个习语是 C类:public b,public a < /Cl>(用子类重复这个特性),但是这在C++中是不起作用的,因为它使<>代码> a < /> >在<代码> c>代码>中含糊。 看来,你只需要添加一点痕迹和用法来回答你自己的问题……
#include <iostream>
template<typename T> struct A {
void func() {
T::func();
}
};
struct B1 : A<B1> {
virtual void func() {
std::cout << "virtual void B1::func();\n";
}
};
struct B2 : A<B2> {
void func() {
std::cout << "void B2::func();\n";
}
};
struct C1 : B1 { };
struct C2 : B2 { };
struct C1a : B1 {
virtual void func() {
std::cout << "virtual void C1a::func();\n";
}
};
struct C2a : B2 {
virtual void func() {
std::cout << "virtual void C2a::func();\n";
}
};
int main()
{
C1 c1;
c1.func();
C2 c2;
c2.func();
B1* p_B1 = new C1a;
p_B1->func();
B2* p_B2 = new C2a;
p_B2->func();
}
结论:A确实具有B函数的虚拟性。在您的特定示例中,不需要动态调度,因为c
的类型在编译时已知。对B::func
的调用将是硬编码的
如果您通过B*
调用func
,那么您将调用一个虚拟函数。但在您精心设计的示例中,这将使您再次访问B::func
从A*
谈论动态分派没有多大意义,因为A
是一个模板类-您不能创建泛型A
,只能创建一个绑定到特定子类的类
您如何实现类A,使得如果B有一个虚拟覆盖,它是动态调度的,而如果B没有,它是静态调度的
正如其他人所注意到的,这个问题真的很难理解,但它让我想起了很久以前学到的一些东西,所以这里有一个很长的机会来回答你的问题:
template<typename Base> class A : private Base
{
public:
void func()
{
std::count << "A::func";
}
};
这会回答您的问题吗?我不确定我是否理解您的问题,但您似乎错过了关键的CRTP演员阵容:
template<class T>
struct A {
void func() {
T& self = *static_cast<T*>(this); // CRTP cast
self.func();
}
};
struct V : A<V> { // B for the case of virtual func
virtual void func() {
std::cout << "V::func\n";
}
};
struct NV : A<NV> { // B for the case of non-virtual func
void func() {
std::cout << "NV::func\n";
}
};
模板
结构A{
void func(){
T&self=*static_cast(this);//CRTP cast
self.func();
}
};
结构V:A{//B用于虚函数的情况
虚空函数(){
std::cout函数是否动态调度取决于两件事:
a) 对象表达式是引用类型还是指针类型
b) 函数(重载解析解析到的)是否为虚拟函数
现在进入您的代码:
C c;
c.func(); // object expression is not of pointer/reference type.
// So static binding
A <B> & ref = c;
ref.func(); // object expression is of reference type, but func is
// not virtual. So static binding
A<D>* ptr = new D;
ptr->func(); // object expression is of pointer type, but func is not
// virtual. So static binding
C;
c、 func();//对象表达式不是指针/引用类型。
//所以静态绑定
A&ref=c;
ref.func();//对象表达式为引用类型,但func为
//不是虚拟的,所以是静态绑定
A*ptr=新的D;
ptr->func();//对象表达式为指针类型,但func不是
//虚拟的,所以是静态绑定
简而言之,“func”不是动态调度的
请注意::抑制虚拟函数调用机制
$10.3/12-“明确的资格认证
范围运算符(5.1)禁止
虚拟的“呼叫”机制
OP2中的代码出现错误,因为只有当“Y”是“X”范围内的静态成员时,才能使用语法X::Y调用“X”范围内的“Y”。添加到常见问题解答中,似乎很有用。也许说明您打算做什么会给您提供更好的解决方案,并说“更好”我主要指的是可维护的,您可以在以后阅读和理解您自己的代码。@the_-drow:这个问题在成为FAQ候选问题之前需要很多帮助。代码示例需要更改以便编译,然后海报需要解释实际行为与所需行为之间的差异,然后可以在如果看起来似乎够一般的话,FAQ就可以了。@ Ben Voigt:这个问题对于那些想了解V-塔尔贝的人来说是非常有用的,而C++在魔罩下又是如何神奇的呢?这与模板专门化、编译时重载解析和通过虚拟函数进行动态调度之间的交互有关,但很难回答有关无法编译的代码行为的问题。实际上,使用CRTP确实让您了解A中的B(这就是CRTP的全部要点)。我可能会被这个问题弄糊涂。如前所述,func
是私有的,因此C.func()
是一个编译错误。B::func()
完全隐藏继承的a::func()
,因此a::func()的唯一可能调用方
是A
,所以是的,它知道B
,但它不知道C
。所以我的第一句话可能应该是“A对(任何可能的)C一无所知”。你可以显式调用隐藏函数,例如C.A::func(),因此A不是“唯一可能的调用方”(如果我们忽略两个func都是私有的)A确实不知道(任何可能的)C,但这个问题只问B。或者更可能的情况是:A*p=new C();p->func();
——这将调用A::func
——如果它当然会编译。A::func()
甚至没有被使用过(如果被使用也不会编译)。错误消息将是“在成员函数中”void A::func()[带T=B1]:错误:没有obje无法调用成员函数“virtual void B1::func()”
class V
{
public:
virtual void func() {}
};
class NV
{
};
class B : public A<V> // makes func() virtual
{
public:
void func()
{
std::count << "B::func";
}
};
class C : public A<NV> // makes func() non-virtual
{
public:
void func()
{
std::count << "C::func";
}
};
template<class T>
struct A {
void func() {
T& self = *static_cast<T*>(this); // CRTP cast
self.func();
}
};
struct V : A<V> { // B for the case of virtual func
virtual void func() {
std::cout << "V::func\n";
}
};
struct NV : A<NV> { // B for the case of non-virtual func
void func() {
std::cout << "NV::func\n";
}
};
struct DV : V {
virtual void func() {
std::cout << "DV::func\n";
}
};
struct DNV : NV {
void func() {
std::cout << "DNV::func\n";
}
};
template<class B>
void call(A<B>& a) {
a.func(); // always calls A<T>::func
}
int main() {
DV dv;
call(dv); // uses virtual dispatch, finds DV::func
DNV dnv;
call(dnv); // no virtual dispatch, finds NV::func
return 0;
}
C c;
c.func(); // object expression is not of pointer/reference type.
// So static binding
A <B> & ref = c;
ref.func(); // object expression is of reference type, but func is
// not virtual. So static binding
A<D>* ptr = new D;
ptr->func(); // object expression is of pointer type, but func is not
// virtual. So static binding