1

我有一些这样的代码:

#include <string>

class another_foo
{
public:
    another_foo(std::string str)
    {
        // something
    }

private:
    // something
};

class foo
{
public:
    foo();

private:
    another_foo obj;
};

foo::foo() : obj(str) // no `: obj("abcde")`, because it is not that simple in real situation.
{
    std::string str = "abcde"; // generate a string using some method. Not that simple in real situation.
    // do something
}

我将初始化obj哪个是foo. 但是这段代码无法编译。如何在初始化列表中使用构造函数主体中的变量?

AFAIK,唯一的方法是将str构造函数生成的代码作为另一个函数分离,然后直接在初始化列表中调用该函数。那是...

#include <string>

class another_foo
{
public:
    another_foo(std::string str)
    {
        // something
    }

private:
    // something
};

class foo
{
public:
    foo();

private:
    another_foo obj;

    // std::string generate_str() // add this
    static std::string generate_str() // EDIT: add `static` to avoid using an invalid member
    {
        return "abcde"; // generate a string using some method. Not that simple in real situation.
    }
};

foo::foo() : obj(generate_str()) // Change here
{
    // do something
}

但是有没有更好的方法?

4

4 回答 4

3

是的,您必须将其移至函数中。如果它是单一用途的东西(仅用于此初始化)并且您可以访问 C++11 lambda,则可以使用单一用途的 lambda。否则,只需像您一样使用成员函数。请注意在其中调用虚函数,因为该对象仍在构建中。如果可能的话,最好static做到。

拉姆达示例:

class foo
{
public:
    foo();

private:
    another_foo obj;
};

foo::foo() : obj([] { return "abcde"; } ())
{
    // do something
}
于 2013-06-20T12:03:38.827 回答
2

但是有没有更好的方法?

简而言之:不,如果您不愿意更改 obj 的分配方式或语义,则不会。

您可以对此进行变体,例如使用 lambda 将 generate_str() 设为静态或更好(如果代码很短):

foo::foo() : obj( []{ return "abcde"; }() )
{
}

但是:如果对象构造需要依赖于其他成员的逻辑,那么您必须确保成员的初始化顺序反映了相互依赖关系(在声明中将它们从独立到依赖排序)或者更好:更改语义obj OR 在堆上分配它。

更改分配会产生构建/破坏成本和非常小的访问成本,因此大多数时候它不是最佳解决方案,但它解决了问题:

class foo
{
public:
    foo();

private:
    std::unique_ptr<another_foo> obj; // no sharing of the instance

};

foo::foo() // obj is null
{
    // do something
    auto result_obj_info = compute_something();
    obj = new another_foo( result_obj_info ); 
    // OR if you use this http://stackoverflow.com/questions/12547983/is-there-a-way-to-write-make-unique-in-vs2012
    obj = std::make_unique<another_foo>( result_obj_info );
}

但是,我建议改为更改another_foo 的语义,使其具有值语义

#include <string>

class another_foo
{
public:

    another_foo(); // this create an invalid anoter_foo, unusable.

    another_foo(std::string str) // this create a valid another_foo
    {
        // something
    }

    // make sure copy/move functions are available, either automatically or manually

    bool is_valid() const;

private:
    // something
};

inline bool is_valid( const another_foo& obj ) { return obj.is_valid(); }

class foo
{
public:
    foo();

private:
    another_foo obj;
};

foo::foo()
{
    assert( is_valid( obj ) == false);
    std::string str = "abcde"; // generate a string using some method. Not just simple like that in real situation.
    // do something
    obj = another_foo( str );
    assert( is_valid( obj ) == true);
}

这样,您的 another_foo 类型就像其资源的句柄一样。如果它不应该被复制,就让它只移动。例如,看看 std::thread 或 std::unique_ptr 是如何工作的。

于 2013-06-20T12:09:24.073 回答
1

编写将在构造期间调用的成员函数时的风险是您可能会在之后更改它以使用某些类的数据成员,这些成员可能在调用时尚未初始化。

最好定义一个外部函数来生成字符串,如下所示:

namespace {
std::string generate_str()
{
    return "abcde"; 
}
}

foo::foo() : obj(generate_str()) 
{
    // do something
}

这样,如果您必须将参数传递给函数,则使用未初始化的数据成员或虚拟成员函数返回值将从构造函数中可见,因此更容易捕获。

于 2013-06-20T12:04:53.960 回答
0

如果它是特定于该类的常量,则可以这样定义:

class foo {
    public:
        foo();
    private:
        static const std::string STR;
        another_foo obj;
};

const std::string foo::STR = "abcde";

foo::foo() : obj(STR)
{
}

编辑
由于它似乎不是一个常数,您可能必须为此工作使用静态成员函数。(或 lambda,您的选择)

class foo {
    static std::string generate_string() const;
};

执行:

std::string foo::generate_string() const {
    return std::string("abcde");
}
于 2013-06-20T12:02:41.880 回答