【问题标题】:Constructor Definition C++ syntax [duplicate]构造函数定义 C++ 语法 [重复]
【发布时间】:2019-04-14 02:30:17
【问题描述】:

这两种构造函数声明有什么区别:

class Fruit {
  private:
    int price;

  public:
    Fruit(int x): price(x)
    {
    }    
};

VS

class Fruit {
  private:
    int price;

  public:
    Fruit(int x)
    {
        price = x;
    }
};

我在继承的情况下看到的第一个。

据我所知,这不是一个重复的问题。如果你发现有人可以关闭这个问题。

【问题讨论】:

  • 两者都不会编译,除非你添加一个 ;声明后:int price;

标签: c++ oop c++11 ctor-initializer


【解决方案1】:

第一个用x初始化price,第二个用它的默认值初始化price(默认构造它;如果是int变量,用一个未定义的值初始化)然后复制xprice

也就是说,第一个几乎等价于

int price = x;

第二个几乎等同于

int price;

price = x;

如果是 int 变量(也考虑编译器的优化),我想没有有效的区别。

但是当price是一个复杂的对象,建设成本很高时,可能会有很大的不同。

正如彼得更好地解释的那样,“对于复杂对象,两者之间的区别并不是构造成本。这是一个问题,即在默认初始化后重新分配是否比一步初始化更昂贵。实际上,两阶段过程是通常比直接初始化更昂贵(通过各种措施),因为可能需要清理默认设置才能更改值。还有异常安全问题 - 如果重新分配或构造引发异常怎么办。”

因此,通常强烈建议使用第一种解决方案(使用正确的值初始化对象)。

另请参阅 Zereges 的回答,该回答指出了第一个方法是唯一可用于为常量成员赋值的事实。

确实你不会写

int const  price;

price = x;  // error: price is const

【讨论】:

  • 可能值得注意的是,对于用户定义的类型,第二个选项调用默认构造函数,这可能不是像int price; 这样的无操作。
  • 哦,你刚刚添加了它:)
  • 对于复杂对象来说,两者之间的区别并不是建造成本。这是一个问题,在默认初始化之后重新分配是否比一步初始化更昂贵。实际上,两阶段过程通常比直接初始化更昂贵(通过各种措施),因为可能需要清理默认设置才能更改值。还有异常安全问题——如果重新分配或构造抛出异常怎么办。
  • @Peter - 我试图解释这一点,但你的解释比我的清楚得多。我只是简单地复制了它。谢谢。
【解决方案2】:

第一个使用initialization list,而另一个不使用,并将x分配给构造函数体内的数据成员price

我们通常prefer to use initialization lists,并尽量保持构造函数的主体简单。

【讨论】:

  • 不幸的是,初始化列表的语法有些丑陋,并且排除了中间右值的使用。
  • 确实@Dai,但仍然有用!
  • 这是不正确的。不可能“在构造函数的主体内初始化数据成员”。那是一个任务。
  • @LightnessRacesinOrbit 很好,已更正,谢谢!
【解决方案3】:

要添加其他答案,第一个选项是初始化const成员的自然方式

struct C
{
    const int val;

    C() : val(5) // Perfectly OK
    {
    }

    C(int) // error: uninitialized const member in 'const int' [-fpermissive]
    {
        val = 5 // error: assignment of read-only member 'C::val'
    }
};

此外,当类具有不可默认构造的类型成员时,这是初始化它们的方法

struct D
{
    struct not_default_constructible
    {
        not_default_constructible(int)
        {
        }
    } var;

    int& ref;

    D(int a) : ref(a), var(5) // Legal
    {
    }

    D(int a, char) // error: uninitialized reference member in 'int&' [-fpermissive]
    { // error: no matching function for call to 'D::not_default_constructible::not_default_constructible()'
        ref = a;
    }
};

【讨论】:

  • 同理,类类型的成员,当该类没有可访问的默认构造函数时,只能使用 mem-initializer-list 进行初始化。
【解决方案4】:

当创建Fruit 时,第二个不会用x 初始化price,因此默认构造它。就像你写的一样:

class Fruit{
private :
    int price

public:
    Fruit(int x) :
        price() // default constructed
    {
        price = x
    }    
}

为了效果,最好用你想赋给它的值来初始化。

【讨论】:

    猜你喜欢
    • 2015-12-01
    • 2014-07-05
    • 2016-07-08
    • 1970-01-01
    • 2016-04-13
    • 2016-07-13
    • 1970-01-01
    • 2020-12-14
    • 2013-02-24
    相关资源
    最近更新 更多