V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
northisland
V2EX  ›  问与答

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

  •  
  •   northisland · 2017-06-19 19:21:17 +08:00 · 1300 次点击
    这是一个创建于 2474 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我 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
    

    • 想问,到底该怎么做,才能实现这个的需求。

    • 另外,谁能把代码中 PHP is the most beautiful language!给输出出来?

    secondwtq
        1
    secondwtq  
       2017-06-19 22:07:50 +08:00   ❤️ 2
    暂时没试,不过发现几个问题:

    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
        2
    xss  
       2017-06-20 09:42:47 +08:00   ❤️ 1
    speakOut 作为 virtual 方法
    这个是多态的典型应用场景
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1200 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 23:13 · PVG 07:13 · LAX 16:13 · JFK 19:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.