Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 虚拟继承和静态继承——在C++;_C++_Oop_Inheritance - Fatal编程技术网

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