简体   繁体   English

有没有办法在C ++中初始化成员变量(类)?

[英]Is there a way to late-initialize a member variable (a class) in C++?

I am coming from the Java background. 我来自Java背景。 I have the following program. 我有以下程序。

#include <string>
#include <iostream>

class First {
    public:
    First(int someVal): a(someVal) {

    }
    int a;
};

class Second {
    public:
    First first;
    Second()  {   // The other option would be to add default value as ": first(0)"
        first = First(123);

    }
};

int main()
{
    Second second;
    std::cout << "hello" << second.first.a << std::endl;
}

In class Second , I wanted to variable first to remain uninitialized until I specifically initialize it in Second()'s constructor . 在课堂Second ,我想变first保持未初始化,直到我特别是在初始化Second()'s constructor Is there a way to do it? 有办法吗? Or am I just left with 2 options?: 或者我只剩下2个选项?:

  1. Provide a parameter-less constructor. 提供无参数构造函数。
  2. Initialize it with some default value and later re-assign the required value. 使用某个默认值对其进行初始化,然后重新分配所需的值。

I can't initialize first in the initializer-list with the right value, since the value is obtained after some operation. 我不能初始化first在初始化列表与正确的价值,因为一些操作后得到的值。 So, the actual required value for first is available in Second() constructor only. 因此, first的实际所需值仅在Second()构造函数中可用。

MY suggestion: Use a function: 我的建议:使用功能:

private: static int calculate_first(int input) {return input*5;}
explicit Second(int input) : first(calculate_first(input)) {}

Base classes will be initialized in the order they're declared in the class inheritance list, and then members will be initialized in the order that they're listed in the class, so the calculation can depend on non-static member-variables and base classes if they have already been initialized. 基类将按照它们在类继承列表中声明的顺序进行初始化,然后成员将按照它们在类中列出的顺序进行初始化,因此计算可以依赖于非静态成员变量和基数如果已经初始化了类。


Alternatively: 或者:

Default constructor, then reassign: 默认构造函数,然后重新分配:

explicit Second(int input) : first(0) { first = input*5; }

Dummy value, then reassign: 虚拟价值,然后重新分配:

boost::optional<First> first;
explicit Second(int input) { first = input*5; }

Use boost::optional: 使用boost :: optional:

std::unique_ptr<First> first;
explicit Second(int input) { first.reset(new First(input*5));}
Second(const Second& r) first(new First(*(r->first))) {}
Second& operator=(const Second& r) {first.reset(new First(*(r->first)));}

Use the heap: 使用堆:

This is tricky and not suggested 
and worse in every way than boost::optional
So sample deliberately missing.
But it is an option.

Placement new: 新位置:

 This is tricky and not suggested and worse in every way than boost::optional So sample deliberately missing. But it is an option. 

Initialize first in the member initializer list. first在成员初始化列表中初始化。

It may help to perform your calculations in a helper function and use a forwarding constructor: 在辅助函数中执行计算并使用转发构造函数可能会有所帮助:

class Second {
public:
    Second() : Second(helper_function()) {}

private:
    Second(int calc): first(calc) {}
    static int helper_function() { return ...; }

    First first;
};

你可以在评论中做你所说的,或者,你可以先做一个指向First的指针并随时给它内存,虽然我不推荐这种方式

One way to separate object lifetimes is to use the heap, make first a pointer and initialize it anytime you like: 分离对象生存期的一种方法是使用堆, first一个指针并在任何时候初始化它:

class Second {
public:
    First* first;
    Second()  { 
        first = new First(123);

    }
};

of course, you'll probably want to use a smart pointer of some sort rather than a raw pointer. 当然,你可能想要使用某种智能指针而不是原始指针。

This sentence is the core of the problem: 这句话是问题的核心:

I can't initialize first in the initializer-list with the right value, since the value is obtained after some operation. 我无法在初始化列表中首先使用正确的值初始化,因为该值是在某些操作之后获得的。

You should know that what you want to do here is not perfect programming style in Java, either . 你应该知道你想要做的事情也不是Java中完美的编程风格 Leaving the field with some default value and then assigning it a bit later after some calculations have been done effectively prevents it from being final , and consequently the class from being immutable. 保留具有某个默认值的字段,然后在完成某些计算后稍后分配它有效地防止它成为final ,从而使类不可变。

In any case, your goal must be to push those calculations directly into the initialization of the member, using private helper functions (which may be static): 在任何情况下,您的目标必须是使用私有帮助函数 (可能是静态的)将这些计算直接推送到成员的初始化中:

class Second {
private:
    First first;

    static int getInitializationData()
    {
        // complicated calculations go here...
        return result_of_calculations;
    }
public:
    Second() : first(getInitializationData()) {}
};

In my opinion, everything else is just a workaround and will complicate your life in the long run. 在我看来,其他一切只是一种解决方法,从长远来看会使你的生活复杂化。

If you don't code to explicitly initialize a member variable, the default initializer is used to initialize it. 如果您不编写显式初始化成员变量的代码,则使用默认初始值设定项对其进行初始化。

The draft C++ standard has the following about initialization of base classes and member variables: C ++标准草案具有以下关于基类和成员变量的初始化:

12.6 Initialization [class.init] 12.6初始化[class.init]

1 When no initializer is specified for an object of (possibly cv-qualified) class type (or array thereof), or the initializer has the form (), the object is initialized as specified in 8.5. 1如果没有为(可能是cv限定的)类类型(或其数组)的对象指定初始化程序,或初始化程序具有表单(),则按8.5中的指定初始化对象。

And

12.6.1 Explicit initialization [class.expl.init] 12.6.1显式初始化[class.expl.init]

1 An object of class type can be initialized with a parenthesized expression-list, where the expression-list is construed as an argument list for a constructor that is called to initialize the object. 1可以使用带括号的表达式列表初始化类类型的对象,其中表达式列表被解释为被调用以初始化对象的构造函数的参数列表。 Alternatively, a single assignment-expression can be specified as an initializer using the = form of initialization. 或者,可以使用=初始化形式将单个赋值表达式指定为初始化程序。 Either direct-initialization semantics or copy-initialization semantics apply; 直接初始化语义或复制初始化语义都适用; see 8.5. 见8.5。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM