c++ CRTP 中判断 Derived 中有没有某个成员函数

Posted WindTaiL的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ CRTP 中判断 Derived 中有没有某个成员函数相关的知识,希望对你有一定的参考价值。


// 省略 HasMember

template <Dervied>
class B 
  static_assert(HasMember<Derived>());


class A : public B<A> 
public:
  void Member();

这样的代码是编译不过的,因为A还没有完全定义时,static_assert就会fail,但是将static_assert放到某个函数里是可以编译过的。

C++ 隐藏继承层次结构中的成员函数,紧盯 CRTP

【中文标题】C++ 隐藏继承层次结构中的成员函数,紧盯 CRTP【英文标题】:C++ hidding of member functions in inheritance hierarchy staring with CRTP 【发布时间】:2013-06-06 23:05:01 【问题描述】:

昨天,我写了一些代码,如果这是好的还是坏的做法,我真的很感激。如果它不好,可能会出什么问题。

构造如下:

可悲的是,基类 A 作为模板来自 API。目标是能够将 A 的派生类放入 std::vector 中。我通过基类 B 实现了这一点,从 A 继承的所有派生类都将从该基类继承。如果没有 B 中的纯虚函数,则会调用 A 中的 foo() 函数。

使用 B 中的纯虚函数,调用 C 中的 foo() 版本。这正是我想要的。

那么这是不好的做法吗?

编辑:

为了消除我的示例代码中的一些误解:

template <class T> 
class A 

public:
    /* ctor & dtor & ... */
    T& getDerived()  return *static_cast<T*>(this); 
    void bar() 
    
        getDerived().foo(); // say whatever derived class T will say
        foo(); // say chicken
    
    void foo()  std::cout << "and chicken" << std::endl; 
;

class B : public A<B>

public:
    /* ctor & dtor */
    virtual void foo() = 0; // pure-virtual 
;

class C : public B

public:
    /* ctor & dtor */
    virtual void foo()  std::cout << "cow"; 
;

class D : public B

public:
    /* ctor & dtor */
    virtual void foo()  std::cout << "bull"; 
;

std::vector 应该同时包含 C 和 D 和

void main()

std::vector<B*> _cows;
_cows.push_back((B*)new C()));
_cows.push_back((B*)new D()));

for(std::vector<B*>::size_type i = 0; i != _cows.size(); ++i)
   _cows[i].bar();


有输出

cow and chicken
bull and chicken

是需要的。

据我所知,除了使用基类之外,没有其他方法可以将派生自模板类的类存储在容器中。如果我为派生类使用基类,例如,B 我必须将向量中的每个实例转换回其正确的类。但是在调用 bar() 时,我不知道确切的类型。

【问题讨论】:

基类中没有虚拟析构函数。 你在 B 中隐藏了 void A::foo()。在 A 中它不是虚拟的 @spiritwolfform 好的,但这是一种不好的做法吗?会出什么严重的问题吗?是的,没有虚拟析构函数,因为这是一个外卖,而不是原始代码。 这意味着你现在有两个方法,所以你可以用_cows[0].foo()来打印cow_cows[0].A&lt;B&gt;::foo()来打印chicken,这是两个独立的方法 @kronos:当您使用主要用于静态多态性的 CRTP 时,为什么要使用 virtual 函数? ***.com/questions/262254/… 【参考方案1】:

我把它称为做可能令人困惑和混淆的事情的坏习惯。

1) 所有基类和子类中的函数名称都应该是虚拟的或非虚拟的。 在继承层次结构中混合覆盖和重载是一个非常糟糕的主意。 没有人真正期待这样的事情。 因此,如果 A::foo 也应该是虚拟的,或者 B 和 C foo 不应该。

2) 基类最好是接口。 因此 A:foo 应该是纯虚拟的,而不是 B::foo。 2b) 如果基类已经提供了默认实现,则不要在子类中声明纯虚拟函数。

【讨论】:

以上是关于c++ CRTP 中判断 Derived 中有没有某个成员函数的主要内容,如果未能解决你的问题,请参考以下文章

C++ 隐藏继承层次结构中的成员函数,紧盯 CRTP

通过指向base,static_cast,crtp,删除模板的指针派生的成员

C++ 混合强类型基类与 CRTP 和返回值类型推导

C++ 静态多态性 (CRTP) 和使用派生类的 typedef

如何推断 CRTP 中的类型?

如何停止在 C++ 中调用不兼容的方法?