在C ++ 11中使用基类运算符来派生类

时间:2013-11-14 20:01:09

标签: c++ templates inheritance c++11 operator-keyword

考虑一下这个例子。

我有一个容器类(A),它重载/实现了各种算术运算符(A::negate())。

我现在希望创建派生类(BC)。

BC应该由A实施所有运营商。

但是,这些运算符应该使用派生类对象作为参数。

B::negate的原型应该是:B B::negate(),而不是A B::negate()

派生类不需要任何自己的字段,但可以实现自己的方法(B::foo()C::bar())。 要求BC不兼容,即B对象无法分配给C对象,或与C中的任何一个一起使用运营商。

以下是示例代码,我希望它如何工作:

struct A {
        int val;

        A negate() {
                return A{-val};
        }
};

struct B: A {void foo(){}};
struct C: A {void bar(){}};

int main() {
        B obj0 = {5};
        B obj1 = obj0.negate();
}

我明白使用标准继承可能是不可能的,而且可能是C ++ 11根本无法做到的,所以我要求尽可能接近它。

我提出的当前最佳解决方案涉及根本不使用继承,而是将整数模板参数添加到基类,将派生类定义为using B = A<1>;using C = A<2>;,并实现仅适用于某些特殊化的成员方法(仅A::foo<1>(){}A::bar<2>(){})。

但是,我对这个解决方案非常不满意。

3 个答案:

答案 0 :(得分:3)

template<typename Child>
struct A {
  Child* self() {
    static_assert( std::is_base_of< A<Child>, Child >::value, "CRTP failure" );
    return static_cast<Child*>(this);
  }
  Child const* self() const {
    static_assert( std::is_base_of< A<Child>, Child >::value, "CRTP failure" );
    return static_cast<Child const*>(this);
  }
  Child negate() {
    return Child{-val};
  }
};
struct B:A<B> {
  explicit B(int v):A<B>(v) {}
};

在这里,我们将有关其子节点的信息注入基类templateB然后可以相对自由地成为正常的班级。

在父级中,您可以self()获取this指针作为B(或其他派生类)。

另一种方法涉及自由功能。您编写了一个免费的negate template函数,用于检查其参数是否来自A,如果是,则返回否定操作,并返回传入类型的否定版本。

这些的混合也有效,你的自由函数需要A<D>并返回D

答案 1 :(得分:0)

如果您不想使用模板:

使A :: negate()受到保护。

在B:

struct B : public A
{
   B & negate()
   {
      A:negate();
      return *this
   }
  /// and so on
}

因为否定在B中定义,它完全隐藏了A中定义的否定,因此B实现被调用并且可以委托给A.

如果您打算隐藏用户的所有A,那么B应该包含A而不是继承它。 (让A ::再次公开)

struct B
{
   private:
   A m_a;
  public:
   B & negate()
   {
      m_a.negate();
      return *this
   }
  /// and so on
}

答案 2 :(得分:0)

协变返回类型:

#include <iostream>

struct A {
    virtual A& operator ! () { std::cout << "A" << std::endl; return *this; }
};

struct B : public A {
    virtual B& operator ! () { std::cout << "B" << std::endl; return *this; }
};

int main() {
    B b;
    A* a = &b;
    ! *a;
}