首页 > 解决方案 > 声明对象而不调用默认构造函数

问题描述

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

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

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

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

public class Foo {
    private boolean b;

    Foo(boolean b) { this.b = b; }
}

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

class Foo {
        bool b_;
    public:
        Foo(bool b) : b_(b) {}
};

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

public static Foo makeFoo(int x) {
    Foo result;
    if (x > 10) { result = new Foo(true); }
    else { result = new Foo(false); }
    return result;
}

但是,如果我在 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;
}

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

标签: c++objectdefault-constructor

解决方案


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

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

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

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

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

显然,这会阻止您在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;
}

如果你不希望它在一个完全独立的函数中,你可以做一个 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;
}

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

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;
}

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


推荐阅读