首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++中的虚继承和静态继承混合

C++中的虚继承和静态继承混合
EN

Stack Overflow用户
提问于 2010-11-19 08:45:04
回答 6查看 2.3K关注 0票数 9

如果你有这样的东西:

代码语言:javascript
复制
#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;
}

func()是动态调度的吗?

如果B有一个虚拟重写,那么你如何实现A类,如果B没有,那么它是动态调度的,而不是静态调度的?

编辑:我的代码没有编译?抱歉,各位。我现在有点不舒服。我的新代码也不能编译,但这是问题的一部分。另外,这个问题是给我的,而不是常见问题。

代码语言:javascript
复制
#include <iostream>

template<typename T> class A
{
public:
    void func()
    {
        T::func();
    }
};

class B : public A<B>
{
public:
    virtual void func()
    {
        std::cout << "in B::func()\n";
    }
};

class C : public B
{
public:
    virtual void func() {
        std::cout << "in C::func()\n";
    }
};
class D : public A<D> {
    void func() {
        std::cout << "in D::func()\n";
    }
};
class E : public D {
    void func() {
        std::cout << "in E::func()\n";
    }
};

int main()
{
  C c;
  c.func();
  A<B>& ref = c;
  ref.func(); // Invokes dynamic lookup, as B declared itself virtual
  A<D>* ptr = new E;
  ptr->func(); // Calls D::func statically as D did not declare itself virtual
  std::cin.get();

  return 0;
}

visual studio 2010\projects\temp\temp\main.cpp(8): error C2352: 'B::func' : illegal call of non-static member function
      visual studio 2010\projects\temp\temp\main.cpp(15) : see declaration of 'B::func'
      visual studio 2010\projects\temp\temp\main.cpp(7) : while compiling class template member function 'void A<T>::func(void)'
      with
      [
          T=B
      ]
      visual studio 2010\projects\temp\temp\main.cpp(13) : see reference to class template instantiation 'A<T>' being compiled
      with
      [
          T=B
      ]
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-11-19 14:56:32

我不确定我明白你在问什么,但看起来你错过了重要的CRTP演员:

代码语言:javascript
复制
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";
  }
};

如果T没有声明自己的函数,这将是无限递归,因为self.func会找到A::func。即使T的派生类(例如下面的DV )声明了自己的函数,但T没有声明,这也是正确的。

使用不同的最终重写器进行测试,以显示派单按照广告的方式工作:

代码语言:javascript
复制
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;
}
票数 2
EN

Stack Overflow用户

发布于 2010-11-19 09:25:25

如何实现类A,如果B有一个虚拟重写,那么它是动态调度的,如果B没有,那么它是静态调度的?

有点矛盾,不是吗?类A的用户可能对B或C一无所知。如果您有对A的引用,了解func()是否需要动态分派的唯一方法就是查阅vtable。由于A::func()不是虚拟的,因此没有对应的条目,因此没有地方放置信息。一旦你把它变成虚拟的,你就会查询到vtable,它就是动态分派。

获得直接函数调用(或内联)的唯一方法是使用非虚函数,而不是通过基类指针进行间接调用。

编辑:我认为在Scala中的习惯用法是class C: public B, public A<C> (使用子类重复特征),但这在C++中不起作用,因为它使A<T>的成员在C中不明确。

票数 1
EN

Stack Overflow用户

发布于 2010-11-19 11:52:45

在您的特定示例中,不需要动态分派,因为c的类型在编译时是已知的。对B::func的调用将是硬编码的。

如果您通过B*调用func,那么您将调用一个虚拟函数。但在您精心设计的示例中,这将使您再次使用B::func

由于A是一个模板类,因此从A*讨论动态分派没有多大意义-您不能创建一个泛型A,只能创建一个绑定到特定子类的泛型类。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4221163

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档