从基类调用派生类的隐藏(非虚拟)方法

Posted

技术标签:

【中文标题】从基类调用派生类的隐藏(非虚拟)方法【英文标题】:Call hidden (non virtual) method of derived class from base 【发布时间】:2019-11-28 11:07:35 【问题描述】:

有没有办法(模板、宏等)在编译时替换common方法对hidden_​​in_derived的调用,以便 Derived 的实例调用它自己的 hidden_​​in_derived没有使 hidden_​​in_derived 在 Base 中虚拟) ?

#include <iostream>

class Base 
public:
    void common() 
        // some calls to other methods
        hidden_in_derived();
        // yet some calls to other methods
    

    void hidden_in_derived() 
        std::cout << "A" << std::endl;
    
;

class Derived : public Base 
public:
    void hidden_in_derived() 
        std::cout << "B" << std::endl;
    
;


int main() 
    Derived d;
    d.common(); // want hidden_in_derived (prints "B") here somehow ?



【问题讨论】:

没有虚拟化 - 这就是虚拟函数的全部意义。 您需要解决的实际问题是什么?为什么不能将hidden_in_derived 设为虚拟? 如果hidden_in_derived()不是Basevirtual函数,那么Base::common()需要手动算出对象this的ACTUAL类型。这是不可能的,除非Base 携带一些为每个派生类唯一设置的信息,并且Base::common() 的实现具有关于每个可能的派生类的信息,并且在派生新类时更新。做这一切的成本(以及由于忘记正确更新Base::common()而导致出错的可能性)意味着将hidden_in_derived()虚拟化会更容易。 您是否需要派生类实际上共享一个公共基础?如果您不这样做,CRTP 可能会起作用。示例:godbolt.org/z/xVcW2T 在我的示例中,没有每个碱基都是唯一的碱基,因此 Derived1 和 Derived2 会有不同的碱基。 【参考方案1】:

将其设为虚拟,然后你甚至可以使用基类 ptr:https://wandbox.org/permlink/tF5Cb4fE5jEhG5Ru

或者就像你对一个对象所做的那样: https://wandbox.org/permlink/W2EJGXwioXjqd1Zx

【讨论】:

您可以使用函数 ptr 或 std::function 并在构造对象期间为其分配 lambda。 Derived 是在 Base 之后构造的,因此它应该始终调用“最衍生”的实现。 wandbox.org/permlink/SCPmaQ4g5PoQzPRi but hidden_in_derived() 在基类中是虚拟的,对吧?在 cmets 中提到了一个 CRTP 模式要质疑。它似乎可以满足我的需要。 wandbox.org/permlink/SCPmaQ4g5PoQzPRi 看起来很有趣。我不知道 lambda 在内部是如何工作的。这样做不会有任何额外的运行时开销(类似于虚拟方法)吗? Lambda 与使用 operator() 创建结构相同,它调用了 lambda 的主体。指向 this 的指针被传递,没有使用虚拟方法。看这里测试一下:cppinsights.io/s/cd71574c @psb lambda 本身与普通方法调用一样便宜(编译器可以内联它,因为它知道一切)。但是,std::function 确实在内部进行类型擦除,这肯定涉及到虚拟方法调用。用std::function 替换虚拟方法是非常没有意义的,而且几乎肯定会导致性能悲观(好的编译器可能会设法内联所有std::function 抽象,但在这种情况下,他们可以首先对虚拟方法做同样的事情. 是的,你正在过早地优化 - 分析你的方法,然后决定。)

以上是关于从基类调用派生类的隐藏(非虚拟)方法的主要内容,如果未能解决你的问题,请参考以下文章

从基类向下转换时是不是可以调用派生对象的虚拟方法?

从基类c ++的向量中的派生类调用虚拟方法[重复]

如何从基类调用派生类方法?

从基类类型的向量访问派生类方法

从基类到派生类的静态转换后找不到成员函数

如何从基类调用派生赋值运算符?