C ++:继承返回基类指针的函数

时间:2015-07-10 16:33:38

标签: c++ inheritance

我有一个基类Base和一个继承它的类Derived。类Base有一个虚函数returnPtrToSelf(),它返回一个指向自身的指针。 Derived的原始成员函数derivedFunc() Base没有。

#include <iostream>

class Base {
public:
    virtual Base* returnPtrToSelf() {
        return this;
    }
};

class Derived : public Base {
public:
    void derivedFunc() {
        std::cout << "i am derived" << std::endl;
    }
}

int main() {
    Derived d;
    d.derivedFunc();                                   // works
    d.returnPtrToSelf()->derivedFunc();                // ERROR
    ((Derived*)d.returnPtrToSelf())->derivedFunc();    // works
}

除非我实施Derived自己的returnPtrToSelf()并返回Derived*,否则错误不会消失。

我正在制作很多派生类,并认为为每个派生类实现此函数的原始版本是很繁琐的。除了这种乏味的方式之外,还有更方便的方法来解决这个错误吗?

2 个答案:

答案 0 :(得分:1)

不,没有。如果derivedFunc确实存在从Base继承的任何东西,那么这应该反映在Base中:

struct Base {
    virtual void func() = 0;
};

struct Derived : Base {
    void func() override { std::cout << "i am derived" << std::endl; }
};

Base* b = new Derived;
b->func();

如果derivedFunc 适用于Derived,那么无论如何都无法从Base访问它。如果Base改为AnotherDerived,该怎么办?在您确实需要致电derivedFunc的情况下,只需让您的功能采用Derived*(或Derived&)代替Base*(或Base&

作为最后的手段,如果确实存在某些情况,您绝对需要在derivedFunc上唯一地呼叫Derived,那么总是存在:

void maybeCallDerivedFunc(Base* b) {
    if (auto d = dynamic_cast<Derived*>(b)) {
        d->derivedFunc();
    }
}

答案 1 :(得分:0)

  

“我正在制作很多派生类,并认为为每个派生类实现此函数的原始版本是很繁琐的。除了这种单调乏味的方法之外,还有更方便的方法来修复错误吗?”

我说这是使用Template Method Pattern的经典案例:

 class Base {
 public:
     void func() {
         funcImpl();
     }
     virtual ~Base() {}
 protected:
     Base() {}
     virtual void funcImpl() = 0;
 };

 class DerivedA : public Base {
 public:
     DerivedA() {}
 protected:
     void funcImpl() {
         // DerivedA special implementation
     }
 };

 class DerivedB : public Base {
 public:
     DerivedB() {}
 protected:
     void funcImpl() {
          // DerivedB special implementation
     }
 };

主要呼叫看起来像

int main() {
    DerivedA dA;
    DerivedB dB;
    dA.func();
    dB.func();
}

如果从Base派生的每个类都应该为Base::func()中正在进行的更复杂的逻辑贡献一些专门的部分,那么这一点特别有用。

这可以通过使用模板化基类(不需要vtable开销)的类似方式实现,并且仅封装在main()函数中应用的强制转换:

 template<typename Derived>
 class Base {
 public:
     void func() {
         static_cast<Derived*>(this)->funcImpl();
     }
 protected:
     Base() {}
 };

 class DerivedA : public Base<DerivedA> {
 public:
      DerivedA {}
 protected:
      friend class Base<DerivedA>;
      void funcImpl() {
          // DerivedA special implementation
      }
 }; 

 class DerivedB : public Base<DerivedB> {
 public:
      DerivedB {}
 protected:
      friend class Base<DerivedB>;
      void funcImpl() {
          // DerivedB special implementation
      }
 }; 

这也是众所周知的CRTP - &gt; 奇怪的重复模板模式