让派生类指针,指向基类目标。用来调用“无中生有”的派生类方法。在 C++中可行么?

2017-06-19 19:21:17 +08:00
 northisland

我 C++玩的不怎么样。尤其是继承。所以想多学习学习。

应用需求:

有一个基类对象,我想在它上面加一部分功能,就做了一个派生类(但派生类没法做到完美继承基类,因为其中基类有一堆的注册函数,搞定太复杂)。

于是,我就想,通过派生类指针 + 基类的对象,来实现功能的添加。


我的思路:

  1. 有个基类
  2. 有基类的对象,base_obj
  3. 声明了一个派生类,重写了基类的几个 virtual 方法
  4. 用派生类的指针 ptr_derived_obj 指向 base_obj
  5. 用 ptr_derived_obj 调用重写的派生类方法

我试了但是不工作不了


原型代码在这里

#include <iostream>
#include <string>
#include <memory>

using std::string;
using std::cout;
using std::endl;
using std::shared_ptr;

class Base {
 public:
  Base(const char * str): token(str) {}
  virtual void addComment() { token+="is the most beautiful language!"; }
  void speakOut() const { cout<<token<<endl; }
 protected:
  string token;
};

class Derived: public Base {
 public:
  Derived(const char* str): Base(str) {}
  void addComment() { token="Python is the most beautiful language!"; }
};

int main() {
  // ----- base_ptr call base_object -----
  shared_ptr<Base> ptr_base_obj(new Base("C++"));
  ptr_base_obj->addComment();
  ptr_base_obj->speakOut();

  // ----- derived_ptr call derived_object -----
  shared_ptr<Derived> ptr_derived_obj(new Derived("PHP"));
  ptr_derived_obj->addComment();
  ptr_derived_obj->speakOut();

  // ----- derived_ptr call base_object -----
  shared_ptr<Base> ptr_base_obj2(new Base("PHP"));
  // downcasting base to derived ptr
  shared_ptr<Derived> ptr_derived_obj2 = std::dynamic_pointer_cast<Derived>(ptr_base_object2);
  ptr_derived_obj2->addComment();
  ptr_derived_obj2->speakOut();

  return 0;
}

执行结果:

C++ is the most beautiful language!
Python is the most beautiful language!
Segmentation fault

1362 次点击
所在节点    问与答
2 条回复
secondwtq
2017-06-19 22:07:50 +08:00
暂时没试,不过发现几个问题:

1. 我在你 po 出的代码里找不到 ptr_base_object2 这个 symbol。
2. 要是想玩 hack 就不要用 dynamic_cast,无论楼主提出的命题是否成立,dynamic_cast 在作用于指针参数时遇到 cast 失败的情况都会返回 nullptr (作用于引用参数时抛出 std::bad_cast ),也就是楼主这个 segfault 是必然的。
3. 标准应该是把这种行为定义为 UB 的,一般实现中应该是可以的(如果你非要从底层的角度抠的话),不过别干在派生类方法中访问派生类成员这种事情,其实你这种行为本来就不应该有,本身是 UB 不说,实际也很容易玩脱的。

具体来说,ctor/dtor 这种机制是 C++ 对象语义中非常必要的东西,有了这一套对象语义才有了 RAII 等 C++ 最独特的特性( Herb Sutter 说过 Java 等处理的是 Garbage,C++ 处理的是 Object ),楼主为了方便直接把这些东西全给 compromise 了,实在不是值得鼓励的做法。
xss
2017-06-20 09:42:47 +08:00
speakOut 作为 virtual 方法
这个是多态的典型应用场景

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/369621

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX