4

考虑这个例子。

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

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

B并且C应该由A.

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

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

派生类不需要任何自己的字段,但可以实现自己的方法(B::foo(), C::bar())。B和不兼容是一个要求C,即B不能将对象分配给C对象,也不能与任何C's 运算符一起使用。

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

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>(){})实现成员方法。

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

4

3 回答 3

4
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) {}
};

template在这里,我们将有关其子 级的信息注入到基类中。B然后相对自由地成为一个正常的班级。

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

另一种方法涉及自由功能。你编写了一个自由negate template函数来检查它的参数是否派生自A,如果是,则进行否定操作,并返回传入类型的否定版本。

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

于 2013-11-14T20:17:37.427 回答
1

协变返回类型:

#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;
}
于 2013-11-14T20:16:09.400 回答
0

如果您不想使用模板:

使 A::negate() 受保护。

在 B 中:

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

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

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

struct B
{
   private:
   A m_a;
  public:
   B & negate()
   {
      m_a.negate();
      return *this
   }
  /// and so on
}
于 2013-11-14T20:11:51.903 回答