一、构造函数的作用
在创建一个新的对象时,自动调用的函数,用来进行“初始化”工作:对这个对象内部的数据成员进行初始化。
二、构造函数的特点
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
如果没有定义赋值构造函数,编译器会自动定义“合成的赋值构造函数”,与其他合成的构造函数,是“浅拷贝”(又称为“位拷贝”)。