声明对象而不调用默认构造函数

Cha*_*man 2 c++ object default-constructor

我是C ++的新手,并且习惯于使用Java。在Java中,我可以选择声明一个对象而不实例化它,并且希望在C ++中也可以这样做。

假设有一些类Foo,在Java中我可以编写Foo bar;声明一个实例,Foo而无需初始化bar。但是,在我编写C ++时Foo bar;,bar通过调用class的默认构造函数进行初始化Foo。

如果我为一个类编写了一个或多个构造函数,这尤其令人烦恼Foo,每个构造函数均具有至少一个参数。在这种情况下,代码将无法编译,并显示类似于以下内容的错误no matching function for call to 'Foo::Foo()'

例如,假设我在Java中具有以下类定义:

public class Foo {
    private boolean b;

    Foo(boolean b) { this.b = b; }
}
Run Code Online (Sandbox Code Playgroud)

以及C ++中相应的类定义:

class Foo {
        bool b_;
    public:
        Foo(bool b) : b_(b) {}
};
Run Code Online (Sandbox Code Playgroud)

在Java中,我可以编写一些方法

class Foo {
        bool b_;
    public:
        Foo(bool b) : b_(b) {}
};
Run Code Online (Sandbox Code Playgroud)

但是,如果我用C ++编写类似的方法,则会出现编译错误:

Foo makeFoo(int x) {
    Foo result; // here, a call is made to Foo::Foo() which doesn't exist, and thus compilation fails
    if (x > 10) { 
        result = Foo(true); // this would probably also fail since I didn't specify a copy-constructor, but I'm not entirely sure
    }
    else {
        result = Foo(false); // as above, I think this would probably fail
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

尽管我给出的示例没有用,但是在编写Java代码时经常使用这种方法。有没有办法在C ++中模拟这种行为?另外,这只是不好的设计吗?如果是这样,您会推荐哪种方法?

Wyc*_*yck 5

如果您不想像Igor(和其他人)在对问题的第一条评论中所说明的那样使用指针来获取参考功能,则可以做几件事。

首先,值类型而不是引用类型的理念是在需要它们之前才创建它们。您倾向于在使用该对象以在该函数的其余部分中获得某种多态功能之前声明引用(可能是某些创建后的通用初始化代码),这是合理的设计,但不能以您编写它的方式表示,因为它将涉及创造价值。

您可以提供一个默认的构造函数并为其提供某些行为-但很明显,您和其他任何人都不想被强迫这样做。

替代方法的本质是将变量移到范围内并返回它。

Foo makeFoo(int x) {
    if (x > 10) { 
        Foo result = Foo(true);
        return result;
    }
    else {
        Foo result = Foo(false);
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,这会阻止您在return之前的if块之后编写通用的创建后初始化代码。为此,您可以在自己的函数中编写if块,并使其返回结果,然后在初始化对象后编写后续代码。

Foo premakeFoo(int x) {
    if (x > 10) { 
        Foo result = Foo(true);
        return result;
    }
    else {
        Foo result = Foo(false);
        return result;
    }
}

Foo makeFoo(int x) {
    Foo result = premakeFoo(x);
    // common post init code can go here.
    return result;
}
Run Code Online (Sandbox Code Playgroud)

如果您不希望在完全独立的函数中使用它,则可以执行lambda。

Foo makeFoo(int x) {
    Foo result = ([=]() {
    if (x > 10) { 
        Foo result = Foo(true);
        return result;
    }
    else {
        Foo result = Foo(false);
        return result;
    })();
    // common post init code can go here.
    return result;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您的情况很小,请使用内联三元表达式。

Foo makeFoo(int x) {
    Foo result = (x > 10) ? Foo(true) : Foo(false); // or just Foo(x>10)
    // common post init code can go here.
    return result;
}
Run Code Online (Sandbox Code Playgroud)

还有其他一些涉及模板的聪明选择,但是它们都围绕着隔离重载构造函数的不同表达式,然后使用赋值来初始化给定一些更复杂表达式的变量的想法。而您想要做的就是获得一种表达式,该表达式以两种不同的方式构造值以覆盖作用域块(跨越if块)。三元和函数是用于在单个表达式中执行if逻辑的选项。