C++拾遗--构造函数


前言

对一个类而言,构造函数恐怕是最重要的一个成员函数了。关于构造函数的细节繁多,并且随着新标准的提出,构造函数有了新的特性。本文来集中探讨下构造函数的那些鲜为人知的一面。

构造函数

构造函数的作用众所周知:在类的对象被创建时,控制对象的初始化和赋值。

构造函数的一般形式:

类名(arg_list);

其中arg_list是用逗号隔开的参数列表。

特点:无返回值类型,且不可加const限制。

默认构造函数

需要特别指出,无参的构造函数是默认的,有参但都有默认参数的构造函数也是默认构造。

------------------------------分割线------------------------------

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码

读C++ Primer 之构造函数陷阱

读C++ Primer 之智能指针

读C++ Primer 之句柄类

将C语言梳理一下,分布在以下10个章节中:

  1. Linux-C成长之路(一):Linux下C编程概要
  2. Linux-C成长之路(二):基本数据类型
  3. Linux-C成长之路(三):基本IO函数操作
  4. Linux-C成长之路(四):运算符
  5. Linux-C成长之路(五):控制流
  6. Linux-C成长之路(六):函数要义
  7. Linux-C成长之路(七):数组与指针
  8. Linux-C成长之路(八):存储类,动态内存
  9. Linux-C成长之路(九):复合数据类型
  10. Linux-C成长之路(十):其他高级议题

举例证明:

#include <iostream>
using namespace std;

class MyClass
{
protected:
 int a = 0;
 int b{1};
public:
 MyClass(int a = 0, int b = 0):a(a), b(b)  //有默认实参的构造方法就是默认构造
 {
  cout << "MyClass(int a = 0, int b = 0)" << endl;
 }

 int getA()const
 {
  return a;
 }
 int getB()const
 {
  return b;
 }
};
int main()
{
 MyClass my;  //调用默认构造
 cout << "a = " << my.getA() << ends << "b = " << my.getB() << endl;
 cin.get();
 return 0;
}

运行

从运行结果,即可验证结论。有参但都有默认参数的构造函数也是默认构造,这一点恐怕是很多人都容易忽略的、

默认构造初始化类的数据成员的规则:

如果存在类内的初始值,用它来初始化成员。

否则,默认初始化。(这个规则虽是标准,但大多数编译器还做不到)

几个概念

1.类内初始值。

在上例代码中,int a = 0; int b{1};这种形式就是类内初始值。后面会说明何时使用类内初始值。

2.默认初始化。

内置类型,如int,double类型等。int->0,double->0.0。就是默认初始化。

类类型,使用该类的默认构造初始化,就是默认初始化。

默认构造并不是总是存在的,若有另一个构造函数(非默认构造)存在,则编译器并不会提供一个无参的默认构造。新标准提出了一种方式:如 MyClass() = default; 关键字 default 的这种使用,表明要求编译器生成一个默认的构造函数。

3.初始值列表

构造函数 MyClass(int a = 0, int b = 0):a(a), b(b){...}  其中 a(a), b(b)就是初始值列表。

4.什么是初始化?什么是赋值?

对象在内存中创建(有了内存实体),第一次有的值,叫做初始化。把原先的值覆盖掉,叫做赋值。

一般情况下,构造函数在初始值列表中完成初始化,在函数体中完成赋值。

这个结论并不好证明,但还是有办法的,办法就是借助:const类型和引用类型。如下代码:

#include <iostream>
using namespace std;

class MyClass
{
protected:
 int a = 0;
 const int ca = 0;
 int& ra;
public:
 MyClass(int a) :a(a), ca(a), ra(this->a){}
 int getA()const
 {
  return a;
 }
 void printCa()const
 {
  cout << "ca = " << ca << endl;
 }
 void printRa()const
 {
  cout << "ra = " << ra << endl;
 }
};
int main()
{
 MyClass my(1);
 cout << my.getA() << endl;
 my.printCa();
 my.printRa();
 cin.get();
 return 0;
}

运行

const类型和引用类型,在创建时,必须进行初始化。若是把 ca = a; ra = this->a; 移到构造函数体内部,则无法通过编译。也就是说,一旦进入构造函数体,初始化就已经完成了。

需要指出,初始值列表的顺序并不代表着实际初始变量的顺序,而成员的声明顺序才是。

更多详情见请继续阅读下一页的精彩内容:

  • 1
  • 2
  • 下一页
【内容导航】
第1页:默认构造 第2页:拷贝构造

相关内容