C++ 类的构造函数详解及实例

2020-01-06 16:06:40王旭

为什么推荐使用初始化列表?

1.在许多类中,初始化和赋值严格来讲都是低效率的:数据成员可能已经被直接初始化了,还要对它进行初始化和赋值。
2.比第一点提到的效率更重要的是,某些类型的数据成员必须要初始化。

       有些类型的成员必须在初始化列表中进行初始化,比如const对象和引用类型对象。它们只能初始化而不能赋值。在执行构造函数体之前必须完成初始化。在函数体内对它们赋值会引发编译错误。

        类类型的成员变量也要特别注意,如果你不对它在初始化列表中的初始化,编译器将会尝试在初始化阶段调用它的默认构造函数给他初始化。如果它没有默认的构造函数,这将会导致运行时错误。另一种情况是你只在构造函数体内对类对象的成员进行了赋值。初始化阶段将会调用该类对象成员的默认构造函数,计算阶段将会调用构造函数体内指定构造函数。意思是该类对象成员调用了两次构造函数,第二次的会覆盖第一次的。

构造函数与隐式类型转换、explicit

       C++支持类型自动转换。可以定义如何将其他类的对象隐式转换为我们的类类型,也可以将我们的类类型对象隐式的转换为其他类型。构造函数有个隐含规则:可以用单个实参类调用的构造函数定义了一个从该形参类型到该类类型的一个隐式转换。有时候这不是你想要的,并且会引发错误。例如你定义了下面的类。


class Box 
{ 
  public: 
  Box(int x=1,int y=1); 
  int length; 
  int width; 
}; 
Box::Box(int x,int y):length(x),width(y) 
{ 
} 

如果你Box box= 2来初始化一个Box对象。编译器将2隐式转换为一个Box对象,相当于调用了构造函数Box(2)。

如果你在需要Box类型参数的函数调用中传入的是一个int实参,将会构造一个临时的Box对象再传入函数作参数。函数结束后,这Box对象也就消失了,这有什么用呢?这几乎肯定是一个错误。对此我们可以:

1.用关键字explicit阻止构造函数定义的隐式转换

       在类构造函数的声明前加上explicit关键字(注意不能在定义中加),可以阻止隐式转换。


class Box 
{ 
  public: 
  explicit Box(int x=1,int y=1); 
  int length; 
  int width; 
}; 

如果你再这样定义一个Box对象:Box box = 2或者将int类型对象作为参数当做Box对象传给某个函数,将会引发编译错误。

2.每次转换,自己显示的使用构造函数。这样可以防止隐式转换。
在需要Box对象实参的的函数调用中用func(Box(2))来调用类的构造函数创建一个临时对象,防止自动的隐式转换。