从基类调用派生类的隐藏(非虚拟)方法
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()
不是Base
的virtual
函数,那么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/SCPmaQ4g5PoQzPRibut 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
抽象,但在这种情况下,他们可以首先对虚拟方法做同样的事情. 是的,你正在过早地优化 - 分析你的方法,然后决定。)以上是关于从基类调用派生类的隐藏(非虚拟)方法的主要内容,如果未能解决你的问题,请参考以下文章