具有初始值的类构造

Jon*_*hon 6 c++

我是C++的新手,以及课程的全部理念 - 我还在读一本书来尝试和学习.我正在阅读的这本书说,当我构建一个类时,我可以通过这样做来指定默认值:

class foo {
public:
   foo(char c, int i);
private:
   char exampleChar;
   int exampleInt;
};

foo::foo(char c, int i):
exampleChar(c),
exampleInt(i)
{}
Run Code Online (Sandbox Code Playgroud)

这段代码(对我来说)看起来非常混乱,并且不遵循我在其他语言中习惯的规则.我的问题是,做上述内容与此之间的区别是什么(下面,我个人认为看起来更清洁)?

foo::foo(char c, int i) {
   exampleChar = c;
   exampleInt = i;
}
Run Code Online (Sandbox Code Playgroud)

我正在考虑的一些事情是:如果大规模地进行性能/效率问题 - 还是完全一样?

Set*_*gie 10

第一种方式,: exampleChar(c), exampleInt(i)称为初始化列表.

如果以第二种方式执行,则两个变量首先默认构造1,然后为它们分配值.(当输入构造函数的实际主体时,默认构造的任何尚未由初始化程序列表初始化的内容.)这是浪费时间,因为您只是覆盖了值.对于类似的小类型int或者char这不是什么大问题,但是当这些成员变量是需要大量循环来构建的大型类型时,您肯定希望使用初始化列表.

第二种方法不会浪费时间给它们一个默认值,然后覆盖它 - 它会将它们的值直接设置为你给它的值(或者如果成员是一个对象,则调用正确的构造函数).

你可以通过这样做看出我们的意思:

class MyClass {
public:
    int _i; // our data

    // default constructor
    MyClass() : _i(0) { cout << "default constructor"; }

    // constructor that takes an int
    MyClass(int i) : _i(i) { cout << "int constructor"; }

    // assignment operator
    void operator=(int i) { _i = i; cout << "assignment operator"; }
};

class OtherClass {
public:
    MyClass c;

    OtherClass() {
        c = 54;
    }
};

OtherClass oc;
Run Code Online (Sandbox Code Playgroud)

你会看到的

default constructor
assignment operator
Run Code Online (Sandbox Code Playgroud)

打印出来.这是两个函数调用,对于其他类,可能很昂贵.

如果您将构造函数更改OtherClass

OtherClass() : c(54) {   }
Run Code Online (Sandbox Code Playgroud)

你会看到的

int constructor
Run Code Online (Sandbox Code Playgroud)

打印出来.只有一个电话与两个电话相比.这是最有效的方式.

初始化程序列表也是必须的

  1. 具有没有默认构造函数的类型.您必须在初始化列表中调用正确的构造函数.

  2. 有一个const你想要给出一些价值的成员(而不是仅仅具有默认值

  3. 有一个参考成员.您必须在这些上使用初始化列表.

tl; dr:这样做是因为它至少和其他方式一样快但从不慢,有时甚至更快.

1对于像int和的内置类型char,它们实际上根本没有构造; 他们只是拥有他们以前所遇到的任何记忆的价值.


Ale*_*ler 5

不同之处在于编译器将始终在第一个用户定义的构造函数语句之前初始化所有成员(按声明顺序).在a char和an int都是基本类型的情况下,'初始化'实际上意味着'没有初始化'.但是,如果您的成员具有执行某些实际工作的构造函数,则将提前调用此构造函数 - 如果您这样做的话

foo::foo() {
    myComplexMember = MyComplexClass(42);
}
Run Code Online (Sandbox Code Playgroud)

在调用代码之前,编译器已经调用了MyComplexClass默认构造函数,这会浪费资源(如果无法访问默认的ctor,则编译错误).

通过使用初始化列表,您可以自定义默认初始化并避免无所事事.显然,这是要走的路.


Yoc*_*mer 5

你可以做的事情就是你无法做到的事情.

  1. 如果其中一个成员没有默认构造函数.这是你在建筑工程中发起会员的唯一方法.(基类也一样)

  2. 您可以为const成员分配值.

  3. 在构造函数开始运行之前,您可以确保类的已定义状态.

  4. 如果成员是引用,则需要在初始化列表中初始化它.因为引用是不可变的,并且只能在开头初始化一次(如const)