除了将值传递给成员之外,构造函数可以做任何艰苦的工作吗?

时间:2014-06-28 03:39:48

标签: c++ constructor

因此,总结一下C ++中的初始化,构造函数可以

  1. 将基元类型初始化为内存中的垃圾值
  2. 自动调用成员的默认构造函数
  3. 使用init list
  4. 中的非平凡构造函数初始化成员对象

    但它无法正确初始化数组。参考: C++: constructor initializer for arrays

    我的问题是:如何在函数体中进行有意义的初始化?在进入大括号之前,所有内容都已经以某种方式初始化。大括号只包含清理工作,例如cout<<“这个对象构建好了!”  。参考: Use of constructor in C++

    如果我想在将参数传递给成员对象的构造函数之前预处理该怎么办?例如:

    class Foo{
    public:
        int x;
        Foo(int y){
            x = y;
        }
    };
    
    class Bar{
    public:
        Foo foo1;
        Bar(int y){
            int z = superComplicatedOperation(y);
            // and all other heavylifting work
            foo1 = A(z);
        }
    };
    

    上面的代码无法编译,因为编译器在构造函数中输入大括号之前尝试初始化foo1。

    我已经看到了通过向Foo提供默认构造函数来解决此问题的建议。所以Bar的构造函数首先将foo1初始化为垃圾值,然后将foo1赋值给ctor体中有意义的东西。这也是引用线程中数组初始化的解决方案。但是,不是“初始化为垃圾价值”的矛盾吗?如果编译器要我这样做,那么就不会抱怨没有默认的ctor。

    总之,ctor应该以用户定义的方式初始化对象,但是我没有看到任何方法来做一个非常重要的初始化。我在这里错过了什么吗?

    =============================================== =================================

    澄清:我问我很清楚Bar(int y):foo(superComplicatedOperation(y))语法。我的问题是如何做得很好。从设计的角度来看,我认为superComplicatedOperation()中的代码确实属于ctors。例如,假设Bar采用2个参数(int x,int y)进行初始化。我们可以想象它们是飞机上的xy坐标。 Foo也采用坐标,但使用不同的参考框架。然后我需要

    Bar(int x,int y):foo(f1(a,b),f2(a,b))
    

    如果ctor有一些参数,这种事情会很快变得丑陋。此外,初始列表看起来很拥挤。

    如果ctor body“触及”成员对象,则意味着init list不会将成员设置为所需的状态,而是一些默认的零状态(例如空向量)。因此,在调用ctor时,会分配Bar的第一个内存,然后成员对象(内存的子块)将经历各个阶段:

    垃圾值/未初始化
    ---初始列表或默认成员ctor --->  默认的“零状态”
    --- ctor body -------------------------->  实际上需要初始状态

    所以初始化应该是一个两步过程?

5 个答案:

答案 0 :(得分:2)

预处理参数非常简单:

class Bar
{
    Foo foo;
    Bar(int y) : foo(superComplicatedOperation(y)) {}
}

或者您可以使用C ++ 11委托构造函数:

class Bar
{
    Foo foo;
    Bar (SuperComplicatedData z) : foo(z) {}
    Bar (int y) : Bar(superComplicatedOperation(y)) {}
}

你可以在构造函数体中做什么?很多东西:填充容器,配置成员对象,设置成员对象关系等等。

答案 1 :(得分:1)

  

[...]构造函数可以

     
      
  1. 将基元类型初始化为内存中的垃圾值
  2.   
  3. 自动调用成员的默认构造函数
  4.   

这是默认初始化,它适用于初始化列表中未指定且在类定义中没有初始值设定项的每个成员。

  
      
  1. 使用init list
  2. 中的非平凡构造函数初始化成员对象   

成员初始化列表也可以初始化原始成员。

  

但它无法正确初始化数组。参考:   C++: constructor initializer for arrays

其中一个答案指出现在可以在C ++ 11中完成。

  

我的问题是:如何在函数中进行有意义的初始化   身体?在进入大括号之前,一切都已经过去了   以某种方式初始化。牙箍只包含清理   工作,像cout<<“这个对象的构造!” 。参考:   Use of constructor in C++

嗯...没有。通常,构造函数体中存在大量逻辑。这绝对不仅仅是为了“清理”。确实,当你进入构造函数体时,每个成员都以某种方式初始化(​​对于基本类型可能包括“根本没有初始化”),但没有任何东西说你不能分配它们或以其他方式修改它们。有时你必须要有某种循环依赖。有时,计算存储值的代码足够长,以至于它在构造函数体内更具可读性。

  

上面的代码无法编译,因为编译器尝试初始化foo1   在构造函数中输入大括号之前。

     

我已经看到了通过提供默认值来解决此问题的建议   Foo的构造函数。

嗯,您可以在示例中执行: foo1(A(superComplicatedOperation(y))

  

因此Bar的构造函数将首先将foo1初始化为   垃圾值,然后将foo1分配给有意义的东西   身体。这也是数组初始化的解决方案   引用线程。但是,不是“初始化为垃圾价值”的矛盾吗?   如果编译器希望我这样做,那么它就不会抱怨   没有默认的ctor。

默认ctor表示使用它构造的对象是有效对象。默认的ctor不一定会使成员未初始化(或“初始化为垃圾值”)。考虑std::vector的默认ctor,最好将其内部状态设置为代表空向量的东西!

更基本的是,构造函数的工作(默认与否)是建立对象的不变量,对象上的函数依赖于该不变量。有些对象可能没有不变量,但很多对象(例如,vector的内部指针最好是有效指针或null)。如果没有默认构造函数,则在没有提供参数时,编译器无法创建有效对象;它不能只给你一些“初始化为垃圾值”的东西,因为它无法知道它是否实际上可以成为该类型的有效对象。

答案 2 :(得分:0)

您可以使用初始化列表,就像您需要初始化的任何成员变量一样。

您可能更喜欢将事物初始化为合理的值,然后使用可以在以后设置值的函数。它不是很干净,但是如果你打算构造很多对象,你可以一次预先计算它们中的许多对象,它可以节省你一些时间,而不是计算每个对象的值。

#include <iostream>

int superComplicatedOperation(int a)
{
    return a * 10;
}

class Foo
{
    public:
    int x;
    Foo(int y)
        : x(y)
    {
    }
};

class Bar
{
    public:
    Foo foo1;
    Bar(int y)
        : foo1(superComplicatedOperation(y))
    {
    }
};

int main()
{
    Bar b(7);
    std::cout << b.foo1.x << "\n";
    return 0;
}

答案 3 :(得分:0)

class Bar {
public:
    Foo foo1;
    Bar(int y) : foo1(superComplicatedOperation(y)) { }
};

您可以使用构造函数初始化列表进行此项工作。它将值传递给成员的Actors以进行第一次创建,这可以防止创建垃圾对象。

答案 4 :(得分:0)

我想我不明白。我在20世纪90年代编写了代码,它有一个包含数百行代码的构造函数,它可以执行各种操作:打开文件,实例化数十个创建链表的对象和基于处理文件数据的数组。它当然可以正确初始化数组。