C++构造函数详解

一、构造函数的作用

在创建一个新的对象时,自动调用的函数,用来进行“初始化”工作:对这个对象内部的数据成员进行初始化。

二、构造函数的特点

1)自动调用(在创建新对象时,自动调用)

2)构造函数的函数名,和类名相同

3)构造函数没有返回类型

4)可以有多个构造函数(即函数重载形式)

三、构造函数的种类

默认构造函数

自定义的构造函数

拷贝构造函数

赋值构造函数

四、默认构造函数

没有参数的构造函数,称为默认构造函数。

1. 合成的默认构造函数

但没有手动定义默认构造函数时,编译器自动为这个类定义一个构造函数。

1)如果数据成员使用了“类内初始值”,就使用这个值来初始化数据成员。【C++11】

2)否则,就使用默认初始化(实际上,不做任何初始化)

 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <string>
 4 
 5 using namespace std;
 6 
 7 // 定义一个“人类”
 8 class Human {
 9 public:  //公有的,对外的
10     void eat(); //方法, “成员函数”
11     void sleep();
12     void play();
13     void work();
14 
15     string getName();
16     int getAge();
17     int getSalary();
18 
19 private:
20     string name;
21     int age = 18;
22     int salary;
23 };
24 
25 void Human::eat() {
26     cout << "吃炸鸡,喝啤酒!" << endl;
27 }
28 
29 void Human::sleep() {
30     cout << "我正在睡觉!" << endl;
31 }
32 
33 void Human::play() {
34     cout << "我在唱歌! " << endl;
35 }
36 
37 void Human::work() {
38     cout << "我在工作..." << endl;
39 }
40 
41 string Human::getName() {
42     return name;
43 }
44 
45 int Human::getAge() {
46     return age;
47 }
48 
49 int Human::getSalary() {
50     return salary;
51 }
52 
53 int main(void) {
54     Human  h1;  // 使用合成的默认初始化构造函数
55     cout << "年龄: " << h1.getAge() << endl;     //使用了类内初始值
56     cout << "薪资:" << h1.getSalary() << endl;  //没有类内初始值
57 
58     system("pause");
59     return 0;
60 }

2.手动定义的默认构造函数

 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <string>
 4 
 5 using namespace std;
 6 
 7 // 定义一个“人类”
 8 class Human {
 9 public:  //公有的,对外的
10     Human(); //手动定义的“默认构造函数”
11     void eat(); //方法, “成员函数”
12     void sleep();
13     void play();
14     void work();
15 
16     string getName();
17     int getAge();
18     int getSalary();
19 
20 private:
21     string name = "Unknown";
22     int age = 28;
23     int salary;
24 };
25 
26 Human::Human() {
27     name = "无名氏";
28     age = 18;
29     salary = 30000;
30 }
31 
32 void Human::eat() {
33     cout << "吃炸鸡,喝啤酒!" << endl;
34 }
35 
36 void Human::sleep() {
37     cout << "我正在睡觉!" << endl;
38 }
39 
40 void Human::play() {
41     cout << "我在唱歌! " << endl;
42 }
43 
44 void Human::work() {
45     cout << "我在工作..." << endl;
46 }
47 
48 string Human::getName() {
49     return name;
50 }
51 
52 int Human::getAge() {
53     return age;
54 }
55 
56 int Human::getSalary() {
57     return salary;
58 }
59 
60 
61 int main(void) {
62     Human  h1;  // 使用自定义的默认构造函数
63     cout << "姓名:" << h1.getName() << endl;
64     cout << "年龄: " << h1.getAge() << endl;    
65     cout << "薪资:" << h1.getSalary() << endl; 
66 
67     system("pause");
68     return 0;
69 }

说明:如果某数据成员使用类内初始值,同时又在构造函数中进行了初始化, 那么以构造函数中的初始化为准。相当于构造函数中的初始化,会覆盖对应的类内初始值。

五、自定义的重载构造函数

 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <string>
 4 
 5 using namespace std;
 6 
 7 // 定义一个“人类”
 8 class Human {
 9 public:  
10     Human();
11     Human(int age, int salary);
12 
13     void eat(); 
14     void sleep();
15     void play();
16     void work();
17 
18     string getName();
19     int getAge();
20     int getSalary();
21 
22 private:
23     string name = "Unknown";
24     int age = 28;
25     int salary;
26 };
27 
28 Human::Human() {
29     name = "无名氏";
30     age = 18;
31     salary = 30000;
32 }
33 
34 Human::Human(int age, int salary) {
35     cout << "调用自定义的构造函数" << endl; 
36     this->age = age;      //this是一个特殊的指针,指向这个对象本身
37     this->salary = salary;
38     name = "无名";
39 }
40 
41 
42 void Human::eat() {
43     cout << "吃炸鸡,喝啤酒!" << endl;
44 }
45 
46 void Human::sleep() {
47     cout << "我正在睡觉!" << endl;
48 }
49 
50 void Human::play() {
51     cout << "我在唱歌! " << endl;
52 }
53 
54 void Human::work() {
55     cout << "我在工作..." << endl;
56 }
57 
58 string Human::getName() {
59     return name;
60 }
61 
62 int Human::getAge() {
63     return age;
64 }
65 
66 int Human::getSalary() {
67     return salary;
68 }
69 
70 
71 int main(void) {
72     Human  h1(25, 35000);  // 使用自定义的默认构造函数
73 
74     cout << "姓名:" << h1.getName() << endl;
75     cout << "年龄: " << h1.getAge() << endl;    
76     cout << "薪资:" << h1.getSalary() << endl; 
77 
78     system("pause");
79     return 0;
80 }

六、拷贝构造函数

1. 手动定义的拷贝构造函数

 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <string>
 4 
 5 using namespace std;
 6 
 7 // 定义一个“人类”
 8 class Human {
 9 public:  
10     Human();
11     Human(int age, int salary);
12     Human(const Human&);
13 
14     void eat(); 
15     void sleep();
16     void play();
17     void work();
18 
19     string getName();
20     int getAge();
21     int getSalary();
22 
23 private:
24     string name = "Unknown";
25     int age = 28;
26     int salary;
27 };
28 
29 Human::Human() {
30     name = "无名氏";
31     age = 18;
32     salary = 30000;
33 }
34 
35 Human::Human(int age, int salary) {
36     cout << "调用自定义的构造函数" << endl; 
37     this->age = age;      //this是一个特殊的指针,指向这个对象本身
38     this->salary = salary;
39     name = "无名";
40 }
41 
42 Human::Human(const Human& man) {
43     cout << "调用自定义的拷贝构造函数" << endl;
44     name = man.name;
45     age = man.age;
46     salary = man.salary;
47 }
48 
49 
50 void Human::eat() {
51     cout << "吃炸鸡,喝啤酒!" << endl;
52 }
53 
54 void Human::sleep() {
55     cout << "我正在睡觉!" << endl;
56 }
57 
58 void Human::play() {
59     cout << "我在唱歌! " << endl;
60 }
61 
62 void Human::work() {
63     cout << "我在工作..." << endl;
64 }
65 
66 string Human::getName() {
67     return name;
68 }
69 
70 int Human::getAge() {
71     return age;
72 }
73 
74 int Human::getSalary() {
75     return salary;
76 }
77 
78 
79 int main(void) {
80     Human  h1(25, 35000);  // 使用自定义的默认构造函数
81     Human  h2(h1);  // 使用自定义的拷贝构造函数
82 
83     cout << "姓名:" << h2.getName() << endl;
84     cout << "年龄: " << h2.getAge() << endl;    
85     cout << "薪资:" << h2.getSalary() << endl; 
86 
87     system("pause");
88     return 0;
89 }

2. 合成的拷贝构造函数

 

  1 #include <iostream>
  2 #include <Windows.h>
  3 #include <string>
  4 #include <string.h>
  5 
  6 using namespace std;
  7 
  8 // 定义一个“人类”
  9 class Human {
 10 public:  
 11     Human();
 12     Human(int age, int salary);
 13     //Human(const Human&);  //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”
 14 
 15     void eat(); 
 16     void sleep();
 17     void play();
 18     void work();
 19 
 20     string getName();
 21     int getAge();
 22     int getSalary();
 23     void setAddr(const char *newAddr);
 24     const char* getAddr();
 25 
 26 private:
 27     string name = "Unknown";
 28     int age = 28;
 29     int salary;
 30     char *addr;
 31 };
 32 
 33 Human::Human() {
 34     name = "无名氏";
 35     age = 18;
 36     salary = 30000;
 37 }
 38 
 39 Human::Human(int age, int salary) {
 40     cout << "调用自定义的构造函数" << endl; 
 41     this->age = age;      //this是一个特殊的指针,指向这个对象本身
 42     this->salary = salary;
 43     name = "无名";
 44 
 45     addr = new char[64];
 46     strcpy_s(addr, 64, "China");
 47 }
 48 
 49 void Human::eat() {
 50     cout << "吃炸鸡,喝啤酒!" << endl;
 51 }
 52 
 53 void Human::sleep() {
 54     cout << "我正在睡觉!" << endl;
 55 }
 56 
 57 void Human::play() {
 58     cout << "我在唱歌! " << endl;
 59 }
 60 
 61 void Human::work() {
 62     cout << "我在工作..." << endl;
 63 }
 64 
 65 string Human::getName() {
 66     return name;
 67 }
 68 
 69 int Human::getAge() {
 70     return age;
 71 }
 72 
 73 int Human::getSalary() {
 74     return salary;
 75 }
 76 
 77 void Human::setAddr(const char *newAddr) {
 78     if (!newAddr) {
 79         return; 
 80     }
 81 
 82     strcpy_s(addr, 64,  newAddr);
 83 }
 84 
 85 const char* Human::getAddr() {
 86     return addr;
 87 }
 88 
 89 
 90 
 91 
 92 
 93 int main(void) {
 94     Human  h1(25, 35000);  // 使用自定义的默认构造函数
 95     Human  h2(h1);  // 使用自定义的拷贝构造函数
 96 
 97     cout << "h1 addr:" << h1.getAddr() << endl;
 98     cout << "h2 addr:" << h2.getAddr() << endl;
 99     
100     h1.setAddr("长沙");
101 
102     cout << "h1 addr:" << h1.getAddr() << endl;
103     cout << "h2 addr:" << h2.getAddr() << endl;
104 
105     system("pause");
106     return 0;
107 }

 

说明:合成的拷贝构造函数的缺点: 使用“浅拷贝”解决方案:在自定义的拷贝构造函数中,使用‘深拷贝

  1 #include <iostream>
  2 #include <Windows.h>
  3 #include <string>
  4 #include <string.h>
  5 
  6 using namespace std;
  7 
  8 // 定义一个“人类”
  9 class Human {
 10 public:
 11     Human();
 12     Human(int age, int salary);
 13     Human(const Human&);  //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”
 14 
 15     void eat();
 16     void sleep();
 17     void play();
 18     void work();
 19 
 20     string getName();
 21     int getAge();
 22     int getSalary();
 23     void setAddr(const char *newAddr);
 24     const char* getAddr();
 25 
 26 private:
 27     string name = "Unknown";
 28     int age = 28;
 29     int salary;
 30     char *addr;
 31 };
 32 
 33 Human::Human() {
 34     name = "无名氏";
 35     age = 18;
 36     salary = 30000;
 37 }
 38 
 39 Human::Human(int age, int salary) {
 40     cout << "调用自定义的构造函数" << endl;
 41     this->age = age;      //this是一个特殊的指针,指向这个对象本身
 42     this->salary = salary;
 43     name = "无名";
 44 
 45     addr = new char[64];
 46     strcpy_s(addr, 64, "China");
 47 }
 48 
 49 Human::Human(const Human &man) {
 50     cout << "调用自定义的拷贝构造函数" << endl;
 51     age = man.age;      //this是一个特殊的指针,指向这个对象本身
 52     salary = man.salary;
 53     name = man.name;
 54     // 深度拷贝
 55     addr = new char[64];
 56     strcpy_s(addr, 64, man.addr);
 57 }
 58 
 59 void Human::eat() {
 60     cout << "吃炸鸡,喝啤酒!" << endl;
 61 }
 62 
 63 void Human::sleep() {
 64     cout << "我正在睡觉!" << endl;
 65 }
 66 
 67 void Human::play() {
 68     cout << "我在唱歌! " << endl;
 69 }
 70 
 71 void Human::work() {
 72     cout << "我在工作..." << endl;
 73 }
 74 
 75 string Human::getName() {
 76     return name;
 77 }
 78 
 79 int Human::getAge() {
 80     return age;
 81 }
 82 
 83 int Human::getSalary() {
 84     return salary;
 85 }
 86 
 87 void Human::setAddr(const char *newAddr) {
 88     if (!newAddr) {
 89         return;
 90     }
 91 
 92     strcpy_s(addr, 64, newAddr);
 93 }
 94 
 95 const char* Human::getAddr() {
 96     return addr;
 97 }
 98 
 99 int main(void) {
100     Human  h1(25, 35000);  // 使用自定义的默认构造函数
101     Human  h2(h1);  // 使用自定义的拷贝构造函数
102 
103     cout << "h1 addr:" << h1.getAddr() << endl;
104     cout << "h2 addr:" << h2.getAddr() << endl;
105 
106     h1.setAddr("长沙");
107 
108     cout << "h1 addr:" << h1.getAddr() << endl;
109     cout << "h2 addr:" << h2.getAddr() << endl;
110 
111     system("pause");
112     return 0;
113 }

七、什么时候调用拷贝构造函数

1. 调用函数时,实参是对象,形参不是引用类型,如果函数的形参是引用类型,就不会调用拷贝构造函数

2. 函数的返回类型是类,而且不是引用类型

3. 对象数组的初始化列表中,使用对象。

 

  1 #include <iostream>
  2 #include <Windows.h>
  3 #include <string>
  4 #include <string.h>
  5 
  6 using namespace std;
  7 
  8 // 定义一个“人类”
  9 class Human {
 10 public:
 11     Human();
 12     Human(int age, int salary);
 13     Human(const Human&);  //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”
 14 
 15     void eat();
 16     void sleep();
 17     void play();
 18     void work();
 19 
 20     string getName();
 21     int getAge();
 22     int getSalary();
 23     void setAddr(const char *newAddr);
 24     const char* getAddr();
 25 
 26 private:
 27     string name = "Unknown";
 28     int age = 28;
 29     int salary;
 30     char *addr;
 31 };
 32 
 33 Human::Human() {
 34     name = "无名氏";
 35     age = 18;
 36     salary = 30000;
 37 }
 38 
 39 Human::Human(int age, int salary) {
 40     cout << "调用自定义的构造函数" << endl;
 41     this->age = age;      //this是一个特殊的指针,指向这个对象本身
 42     this->salary = salary;
 43     name = "无名";
 44 
 45     addr = new char[64];
 46     strcpy_s(addr, 64, "China");
 47 }
 48 
 49 Human::Human(const Human &man) {
 50     cout << "调用自定义的拷贝构造函数" << "参数:" << &man
 51          << " 本对象:" << this << endl;
 52 
 53     age = man.age;      //this是一个特殊的指针,指向这个对象本身
 54     salary = man.salary;
 55     name = man.name;
 56     // 深度拷贝
 57     addr = new char[64];
 58     strcpy_s(addr, 64, man.addr);
 59 }
 60 
 61 void Human::eat() {
 62     cout << "吃炸鸡,喝啤酒!" << endl;
 63 }
 64 
 65 void Human::sleep() {
 66     cout << "我正在睡觉!" << endl;
 67 }
 68 
 69 void Human::play() {
 70     cout << "我在唱歌! " << endl;
 71 }
 72 
 73 void Human::work() {
 74     cout << "我在工作..." << endl;
 75 }
 76 
 77 string Human::getName() {
 78     return name;
 79 }
 80 
 81 int Human::getAge() {
 82     return age;
 83 }
 84 
 85 int Human::getSalary() {
 86     return salary;
 87 }
 88 
 89 void Human::setAddr(const char *newAddr) {
 90     if (!newAddr) {
 91         return;
 92     }
 93 
 94     strcpy_s(addr, 64, newAddr);
 95 }
 96 
 97 const char* Human::getAddr() {
 98     return addr;
 99 }
100 
101 
102 void test(Human man) {
103     cout << man.getSalary() << endl;
104 }
105 
106 void test2(Human &man) { //不会调用拷贝构造函数,此时没有没有构造新的对象
107     cout << man.getSalary() << endl;
108 }
109 
110 Human test3(Human &man) {
111     return man;
112 }
113 
114 Human& test4(Human &man) {
115     return man;
116 }
117 
118 
119 int main(void) {
120     Human h1(25, 35000);  // 调用默认构造函数
121     Human h2(h1);         // 调用拷贝构造函数
122     Human h3 = h1;          // 调用拷贝构造函数
123 
124     test(h1);              // 调用拷贝构造函数
125     test2(h1);              // 不会调用拷贝构造函数
126     test3(h1);            // 创建一个临时对象,接收test3函数的返回值,调用1次拷贝构造函数
127     Human h4 = test3(h1); // 仅调用1次拷贝构造函数,返回的值直接作为h4的拷贝构造函数的参数
128     test4(h1);            // 因为返回的是引用类型,所以不会创建临时对象,不会调用拷贝构造函数
129     
130     Human men[] = { h1, h2, h3 }; //调用3次拷贝构造函数
131 
132     system("pause");
133     return 0;
134 }

 

八、赋值构造函数

  1 #include <iostream>
  2 #include <Windows.h>
  3 #include <string>
  4 #include <string.h>
  5 
  6 using namespace std;
  7 
  8 // 定义一个“人类”
  9 class Human {
 10 public:
 11     Human();
 12     Human(int age, int salary);
 13     Human(const Human&);  //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”
 14     Human& operator=(const Human &);
 15 
 16     void eat();
 17     void sleep();
 18     void play();
 19     void work();
 20 
 21     string getName();
 22     int getAge();
 23     int getSalary();
 24     void setAddr(const char *newAddr);
 25     const char* getAddr();
 26 
 27 private:
 28     string name = "Unknown";
 29     int age = 28;
 30     int salary;
 31     char *addr;
 32 };
 33 
 34 Human::Human() {
 35     name = "无名氏";
 36     age = 18;
 37     salary = 30000;
 38 }
 39 
 40 Human::Human(int age, int salary) {
 41     cout << "调用自定义的构造函数" << endl;
 42     this->age = age;      //this是一个特殊的指针,指向这个对象本身
 43     this->salary = salary;
 44     name = "无名";
 45 
 46     addr = new char[64];
 47     strcpy_s(addr, 64, "China");
 48 }
 49 
 50 Human::Human(const Human &man) {
 51     cout << "调用自定义的拷贝构造函数" << "参数:" << &man
 52          << " 本对象:" << this << endl;
 53 
 54     age = man.age;      //this是一个特殊的指针,指向这个对象本身
 55     salary = man.salary;
 56     name = man.name;
 57     // 深度拷贝
 58     addr = new char[64];
 59     strcpy_s(addr, 64, man.addr);
 60 }
 61 
 62 
 63 Human& Human::operator=(const Human &man) {
 64     cout << "调用" << __FUNCTION__ << endl;
 65     if (this == &man) {
 66         return *this; //检测是不是对自己赋值:比如 h1 = h1;
 67     }
 68 
 69     // 如果有必要,需要先释放自己的资源(动态内存)
 70     //delete addr;
 71     //addr = new char[ADDR_LEN];
 72 
 73     // 深拷贝
 74     strcpy_s(addr, ADDR_LEN, other.addr);
 75 
 76     // 处理其他数据成员
 77     name = man.name;
 78     age = man.age;
 79     salary = man.salary;
 80 
 81     // 返回该对象本身的引用, 以便做链式连续处理,比如 a = b = c;
 82     return *this;
 83 }
 84 
 85 
 86 void Human::eat() {
 87     cout << "吃炸鸡,喝啤酒!" << endl;
 88 }
 89 
 90 void Human::sleep() {
 91     cout << "我正在睡觉!" << endl;
 92 }
 93 
 94 void Human::play() {
 95     cout << "我在唱歌! " << endl;
 96 }
 97 
 98 void Human::work() {
 99     cout << "我在工作..." << endl;
100 }
101 
102 string Human::getName() {
103     return name;
104 }
105 
106 int Human::getAge() {
107     return age;
108 }
109 
110 int Human::getSalary() {
111     return salary;
112 }
113 
114 void Human::setAddr(const char *newAddr) {
115     if (!newAddr) {
116         return;
117     }
118 
119     strcpy_s(addr, 64, newAddr);
120 }
121 
122 const char* Human::getAddr() {
123     return addr;
124 }
125 
126 
127 void test(Human man) {
128     cout << man.getSalary() << endl;
129 }
130 
131 void test2(Human &man) { //不会调用拷贝构造函数,此时没有没有构造新的对象
132     cout << man.getSalary() << endl;
133 }
134 
135 Human test3(Human &man) {
136     return man;
137 }
138 
139 Human& test4(Human &man) {
140     return man;
141 }
142 
143 
144 int main(void) {
145     Human h1(25, 35000);  // 调用默认构造函数
146 
147       // 特别注意,此时是创建对象h2并进行初始化,调用的是拷贝构造函数,
148     // 不会调用赋值构造函数
149     Human h2 = h1;  
150 
151     h2 = h1; //调用赋值构造函数
152     h2 = test3(h1); //调用赋值构造函数
153 
154     Human h3 = test3(h1); //调用拷贝构造函数
155 
156     system("pause");
157     return

如果没有定义赋值构造函数,编译器会自动定义“合成的赋值构造函数”,与其他合成的构造函数,是“浅拷贝”(又称为“位拷贝”)。

 

上一篇:mono touch中,给顶层容器添加遮罩


下一篇:迭代加深搜索与埃及分数求解