所以我最近不小心从基类的构造函数调用了一些虚函数,即Calling virtual functions inside constructors。
我意识到我不应该这样做,因为虚拟函数的重写不会被调用,但我如何才能实现一些类似的功能呢?我的用例是,我希望在构造对象时运行一个特定的函数,我不希望编写派生类的人不得不担心这是在做什么(因为当然他们可以在派生类构造函数中调用这个东西)。但是,需要反过来调用的函数恰好调用了一个虚函数,我希望允许派生类在需要时重写它。
但是因为一个虚函数被调用,我不能把这个函数放在基类的构造函数中,然后让它自动运行。所以我好像被卡住了。
有没有其他方法可以达到我的目的?
edit:我碰巧使用CRTP从基类访问派生类中的其他方法,我可以使用它来代替构造函数中的虚函数吗?还是说,现在的问题基本上是一样的?我想如果被调用的函数是静态的,也许它可以工作?
edit2:也刚刚发现这个类似的问题:Call virtual method immediately after construction
6条答案
按热度按时间sqserrrh1#
如果真的需要,你可以进入工厂。
您可以执行以下操作:
lx0bsm1f2#
要做到这一点没有简单的方法。一种选择是使用所谓的虚拟构造函数习惯用法,隐藏基类的所有构造函数,并公开静态“create”-这将动态创建一个对象,调用它的虚拟重写并返回(智能)指针。
这是丑陋的,更重要的是,限制您动态创建的对象,这不是最好的事情。
然而,最好的解决方案是尽可能少地使用OOP。C++的优势(与流行的观点相反)在于它的非OOP特性。想想看-标准库中唯一的多态类家族是流,每个人都讨厌它(因为它们是多态的!)
eiee3dmh3#
如果你看看其他人是如何解决这个问题的,你会注意到他们只是把调用初始化函数的责任转移给了客户端。以MFC的
CWnd
为例:你有构造函数和Create
,这是一个虚函数,你必须调用它才能有一个正确的CWnd
示例化:* “这些是我的规则:构造,然后初始化;“你要听话,否则你会有麻烦的。是的,它容易出错,但它比替代方案更好:***“有人认为这条规则是一个实现工件。事实并非如此。事实上,实现从构造函数调用虚函数的不安全规则会明显更容易,就像从其他函数调用虚函数一样。但是,这意味着不能编写依赖于基类建立的不变量的虚函数。这将是一个可怕的混乱。我认为他的意思是,当你的构造函数调用从基类向下时,设置虚表指针指向派生类的VT会更容易,而不是不断地将它更改为当前类的VT。
我意识到我不应该这样做,因为虚拟函数的重写不会被调用,...
假设对虚函数的调用将以您想要的方式工作,您不应该这样做,因为不变量。
如果可以通过
D
的VT从B
调用D::f
呢?您将使用一个未初始化的指针,这很可能导致崩溃。但是,如何实现类似的功能呢?
如果你愿意打破规则,我想可能会得到所需的虚表的地址,并从构造函数调用虚函数。
hm2xizp94#
我希望在构造对象时运行一个特定的函数,[…]它]反过来又调用了一个虚函数,我想让派生类能够在需要时重写它。
如果你愿意接受两个限制,这很容易做到:
1.整个类层次结构中的构造函数必须是非公共的,因此
1.必须使用工厂模板类来构造派生类。
这里,“特定函数”是
Base::check
,虚函数是Base::method
。首先,我们创建基类。它只需要满足两个要求:
1.它必须与它的checker类
MakeBase
成为朋友。我假设您希望Base::check
方法是私有的,并且只能由工厂使用。当然,如果它是公共的,就不需要MakeBase
。1.构造函数必须受到保护。
https://github.com/KubaO/stackoverflown/tree/master/questions/imbue-constructor-35658459
模板化的CRTP工厂派生自一个基类,该基类是
Base
的朋友,因此可以访问私有检查器方法;它还可以访问受保护的构造函数,以便构造任何派生类。如果你不小心在一个不是从
Base
派生的类上使用工厂类,它会发出一个可读的编译时错误消息:派生类必须具有受保护的构造函数:
输出:
zi8p0yeb5#
你想要这个,或者需要更多的细节。
utugiqy66#
我会为基类写一个构造函数,它调用你想要的函数并继承构造函数
希望有帮助!(当然,只有当基构造函数处理派生类的一般功能时,这才是方便的)