对基本构造函数的条件调用
Posted
技术标签:
【中文标题】对基本构造函数的条件调用【英文标题】:Conditional call to base constructor 【发布时间】:2018-06-12 14:56:05 【问题描述】:目前,我有一个带有两个不同构造函数的基础类:
class Base
public:
Base(std::string filname)...
Base(int a, int b) ...
;
和基类的派生类。我想做的是在派生类的构造函数中选择哪个构造函数调用,而不是在初始化列表中。像这样的:
class Derived : public Base
public:
Derived()
if( /* exists("myFile") */ )
this->Base("myFile");
else
this->Base(1,2);
有可能这样做吗?还是因为基类在派生类之前初始化,所以调用基构造函数的唯一方法是在初始化列表中?
谢谢
【问题讨论】:
将调用哪个基本构造函数在编译时确定。没有办法解决这个问题。也许你可以得到你想要的,但在本地构建一个Base
并移动构建实际的基础。否则,您可能希望将该逻辑放入您的 Base
构造函数中。
可以修改Base
类的代码吗?
顺便说一句,if file_exists open_file
是一个 TOCTOU 错误。
【参考方案1】:
调用哪个基本构造函数的选择发生在函数体之前,并且没有办法在运行时像那样更改它。但是,您也许可以接近。如果基类也有一个移动构造函数,或者你可以添加一个,你可以使用它:
class Derived : public Base
public:
Derived()
: Base exists("myFile") ? Base"myFile" : Base1, 2
这将调用exists("myFile")
;如果返回true
,它将使用第一个构造函数构造一个临时的Base
,如果它返回false
,它将使用第二个构造函数构造一个临时的Base
。无论哪种方式,它都会使用这个临时构造 actual 基础子对象。
【讨论】:
同样,这里没有条件调用基类构造函数。它总是使用复制构造函数/移动构造函数无条件构造/根据基类实现导致编译错误。 @VTT 没有条件调用复制/移动构造函数。有条件调用 string/two ints 构造函数,这是所需要的。由于 C++17 实际上 no 调用了复制/移动构造函数,就好像它直接选择了哪个构造函数用于基本子对象。 "Since C++17" 是一个重要的限定词!除此之外,这是最好的答案 这只适用于 Base"myFile" 是可实例化的。如果 Base 类是抽象基类,则它不起作用。在这种情况下有什么替代方案吗? 等等,不,我错了。您可以使用私有委托构造函数 (en.cppreference.com/w/cpp/language/…) 和三元运算符,类似于此处使用基构造函数的方式。不过,这可能会导致构造函数中出现一些代码重复。【参考方案2】:你可以通过引入工厂函数来模拟:
class Base
public:
Base(std::string filname);
Base(int a, int b);
;
class Derived : public Base
Derived(std::string filname) : Base(filname)
Derived(int a, int b) : Base(a, b)
public:
static Derived create()
if( /* exists("myFile") */ )
return Derived("myFile");
else
return Derived(1,2);
;
int main()
auto d = Derived::create();
或者,如果不需要从Base
派生,则可以将Base
的实例作为成员(std::unique_ptr
或std::aligned_storage
),您可以随意初始化。
【讨论】:
虽然这些是有效的解决方法,但这里没有条件调用基类构造函数。它总是使用复制构造函数/移动构造函数无条件构造/根据基类实现导致编译错误。【参考方案3】:根据@DanielH 在他的回答中的评论,我开发了一种替代解决方案,它也适用于 C++11 中的抽象基类:
#include <iostream>
struct Base
Base(int x)
std::cout << "Base x = " << x << std::endl;
Base()
std::cout << "Base default" << std::endl;
virtual void foo() = 0;
;
struct Derived : Base
struct TagA ;
struct TagB ;
Derived(bool condition)
: Derived(condition ? DerivedTagA() : DerivedTagB())
void foo() override
private:
Derived(TagA dummy)
: Base(42)
std::cout << "Derived A dummy" << std::endl;
Derived(TagB dummy)
std::cout << "Derived B dummy" << std::endl;
;
int main()
std::cout << "Construct Derived with false" << std::endl;
Derived x(false);
std::cout << "Construct Derived with true" << std::endl;
Derived y(true);
【讨论】:
以上是关于对基本构造函数的条件调用的主要内容,如果未能解决你的问题,请参考以下文章