对基本构造函数的条件调用

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_ptrstd::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);
  


【讨论】:

以上是关于对基本构造函数的条件调用的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中,您需要调用基本构造函数吗?

从构造函数的主体调用超类构造函数

在 perl 中调用基本构造函数

swift学习第十三天:类的构造函数

Java 从基本构造函数调用基本方法

为啥在尝试调用采用动态参数的基本构造函数/方法时会出现此编译错误?