如何继承成员函数,使其始终返回对派生实例的引用

How to inherit a member function so that it always returns a reference to the derived instance?

本文关键字:返回 派生 引用 实例 何继承 继承 函数 成员      更新时间:2023-10-16

我正在研究一个迭代器家族,其中所有的迭代器类X都有共同的X& operator++() {++x; return *this},因此将其放在一个公共基类中似乎是一个好主意。不幸的是,返回类型改变了,因为它应该总是返回对派生类的引用。

下面说明了这个问题。我希望f()工作,但我能想出的唯一解决办法是g()h(),这是不令人满意的:

struct A {
    A& f() {return *this;}
    template <typename T>
    T& g() {return *(T*)this;}
    template <typename T>
    T& h(T& unused) {return *(T*)this;}
};
struct B : A {
    int x;
    B(int x) : x(x) {}
};
int main() {
    B b(12);
    //B b1 = b.f();   // error: conversion from 'A' to non-scalar type 'B' requested
    B b2 = b.g<B>();  // works
    B b3 = b.h(b);    // works
}

是否有办法使B b1 = b.f();工作?也许使用c++ 11的特性?

使用CRTP:

template<class Derived>
struct A {
    Derived& f() {return static_cast<Derived&>(*this);}
};
struct B : A<B> {
    int x;
    B(int x) : x(x) {}
};

F可以返回A,所以你不能将结构体A存储在结构体b中,但是你可以用指针做相反的事情。

    struct A {
  A& f() {return *this;}
  template <typename T>
  T& g() {return *(T*)this;}
  template <typename T>
  T& h(T& unused) {return *((T *)this);}
};
struct B : A {
  int x;
  B(int x) : x(x) {}
  B(const B & other) : x(other.x) {}
};
int main() {
  A  *b = new B(12);
  A *b1 = new B( (const B&)b->f());                                                                                 
  B b2 = b->g<B>();                                                                                                                                                                                 
  A b3 = B->h(*b);                                                                                                                                                             
}

@ecatmur的答案解决了指定的问题,但不幸的是,CRTP不会比这更进一步。考虑有两层继承的情况:

template <typename D>
struct A {
    D& f() {return *static_cast<D*>(this);}
};
template <typename D>
struct B : A<D> {
    int x;
    B(int x=0) : x(x) {}
};
struct C : B<C> {
    double y;
    C(double y=0.) : y(y) {}
};
int main() {
   C c(12.5);
   C c1 = c.f();   // works
}

如果只需要实例化C,这可以正常工作,但现在似乎完全不可能实例化B:

int main() {
   B<B> b;   // error: type/value mismatch at argument 1 in template parameter list
}

我尝试了一堆变化,包括typenametemplate关键字,但没有成功地获得B的实例。也不能使用递归默认模板实参:

template <typename D=B> struct B : A<D> {};    // error

因此,CRTP似乎只在单继承情况下是一个好主意。

我最终用简单的解决方案来返回对基类A&的引用。由于这种方式不会丢失信息,派生类总是可以将返回的引用强制转换为派生类型:

struct A {
    A& f() {return *this;}
};
struct B : A {
    int x;
    B(int x=0) : x(x) {}
};
struct C : B {
    double y;
    C(double y=0.) : y(y) {}
};
int main() {
    B b(12);
    B b1 = (B&)b.f();  // works
    C c(12.5);
    C c1 = (C&)c.f();  // works
}

因此,似乎正确的方法是只返回基类引用,并在必要时在派生类中强制转换。