C++的构造函数是用来对对象初始化操作,下面将对几种构造函数使用上进行详细说明。
默认构造函数创建对象的时候且不传递任何参数的时候自动调用
合成默认构造函数(编译器自动创建)创建对象的时候不传递任何参数,用户在程序没有定义默认函数,那么由编译器自动创建。
1)类成员数据没有类内初始值,使用默认初始化实际不做任何操作。
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); int getClassNum(); void setAddr(); private: // 保护类内属性 string className; char* addr; int classNum; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } void Cls::setAddr() { } int main() { Cls c1; // 此时调用合成默认参数构造函数 cout << c1.getClassNum() << endl; system("pause"); return 0; }
输入、输出:
0
结论:没有任何意义的默认构造函数
2)当类内数据有初始化的值时,编译器创建的合成默认构造使用这个值对创建的对象初始化。
类内初始值在C++11及以上的标准才支持
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); int getClassNum(); void setAddr(); private: // 保护类内属性 // 类内数据有初始值 string className = "大班"; char* addr = NULL; int classNum = 12; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } void Cls::setAddr() { } int main() { Cls c1; // 此时调用合成默认参数构造函数,并且把类内初始化值拿来给对象初始化 cout << c1.getClassNum() << endl; cout << c1.getClassName() << endl; system("pause"); return 0; }
输入、输出:
12 大班
结论:当类内数据全部都使用了初始值,然后使用合成默认构造函数才有意义
用户定义默认构造函数手动定义的默认构造函数是最好的,因为规范化的时候类内初始是不存在的。所以我们创建对象的时候一般通过默认构造函数来进行数据初始化。
代码:
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); int getClassNum(); void setAddr(); // 自定义默认构造函数:没有返回值和类名相同 Cls(); private: // 保护类内属性 string className; char* addr; // 当自定义默认构造函数也修改了改数据,那么该类内初始值既被覆盖 int classNum = 12; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } void Cls::setAddr() { } // 使用自定义默认构造函数来进行对象初始化 Cls::Cls() { cout << "自定义默认构造函数被调用" << endl; className = "小班"; addr = NULL; classNum = 13; } int main() { Cls c1; // 此时调用自定义默认参数构造函数,然后对对象初始 cout << c1.getClassNum() << endl; // 用户自定义初始化值。覆盖了类内初始值。 cout << c1.getClassName() << endl; cout << "**************" << endl; Cls c2; // 此时调用自定义默认参数构造函数,然后对对象初始 cout << c2.getClassNum() << endl; cout << c2.getClassName() << endl; system("pause"); return 0; }
输入、输出:
自定义默认构造函数被调用 13 小班 ************** 自定义默认构造函数被调用 13
结论:当某个数据成员在类内初始化后,同时也在构造函数中进行了初始化操作,那么以构造函数中的为准。
相当于构造函数中的初始化,会覆盖类内初始化。
创建对象的传递参数,调用该构造函数。
自定义带参数的构造函数可以发生重载。
代码:
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); int getClassNum(); char* getAddr(); void setAddr(); void descrirition(); Cls(); // 自定义默认构造函数:没有返回值和类名相同 Cls(int classNum, string className, const char* addr); // 自定义参数构造函数 Cls(int classNum, string className); // 自定义参数构造函数重载 private: // 保护类内属性 string className; char* addr = NULL; int classNum; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } char* Cls::getAddr() { return addr; } void Cls::setAddr() { } // 自定义默认构造函数来进行对象初始化 Cls::Cls() { cout << "自定义默认构造函数被调用" << endl; className = "小班"; addr = NULL; classNum = 11; } void Cls::descrirition() { cout << "addr: " << addr << " className:" << className << "classNum:" << classNum << endl; } // 自定义参数构造函数 Cls::Cls(int classNum, string className,const char* addr) { cout << "自定义参数构造函数-重载1" << endl; this->classNum = classNum; this->className = className; this->addr = (char*)addr; } // 自定义参数构造函数重载 Cls::Cls(int classNum, string className) { cout << "自定义参数构造函数-重载2" << endl; this->classNum = classNum; this->className = className; } int main() { Cls c1(13, "大班"); cout << " className:" << c1.getClassName() << " classNum:" << c1.getClassNum() << endl; Cls c2(12, "中班", "北京"); c2.descrirition(); system("pause"); return 0; }
输入、输出:
自定义参数构造函数-重载2 className:大班 classNum:13 自定义参数构造函数-重载1 addr: 北京 className:中班classNum:12
结论:
1、自定义带参数构造函数用于创建对象带参数
2、自定义带参数构造函数可以发生重载
拷贝函数在什么时候被调用?
拷贝构造函数也有合成拷贝构造函数(编译器自动创建)和自定义拷贝构造函数之分。
合成拷贝构造函数是浅拷贝,而我们自定义的一般使用深拷贝。
深浅拷贝一般针对的是指针,在堆区开辟内存空间,后面程序中我们会细讲。
合成拷贝构造函数编译器自动创建,浅拷贝。
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); int getClassNum(); char* getAddr(); void setAddr(const char* addr); void descrirition(); Cls(); // 自定义默认构造函数:没有返回值和类名相同 Cls(int classNum, string className, const char* addr); // 自定义参数构造函数 Cls(int classNum, string className); // 自定义参数构造函数重载 private: // 保护类内属性 string className; char* addr = NULL; int classNum; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } char* Cls::getAddr() { return addr; } void Cls::setAddr(const char* addr) { strcpy_s(this->addr, 20, addr); } // 自定义默认构造函数来进行对象初始化 Cls::Cls() { cout << "自定义默认构造函数被调用" << endl; className = "小班"; addr = NULL; classNum = 11; } void Cls::descrirition() { cout << "addr: " << addr << " className:" << className << "classNum:" << classNum << endl; } // 自定义参数构造函数 Cls::Cls(int classNum, string className,const char* addr) { cout << "自定义参数构造函数-重载1" << endl; this->classNum = classNum; this->className = className; this->addr = new char[20]; strcpy_s(this->addr, 20, addr); } // 自定义参数构造函数重载 Cls::Cls(int classNum, string className) { cout << "自定义参数构造函数-重载2" << endl; this->classNum = classNum; this->className = className; } int main() { Cls c1(12, "中班", "北京"); // 使用已创建的对象来创建对象调用,拷贝构造函数 Cls c2 = c1; // 这里针对指针数据只是复制了地址 Cls c3(c1); c1.descrirition(); c2.descrirition(); cout << "修改" << endl; c1.setAddr("南京"); c1.descrirition(); c2.descrirition(); system("pause"); return 0; }
输入、输出:
自定义参数构造函数-重载1 addr: 北京 className:中班classNum:12 addr: 北京 className:中班classNum:12 修改 addr: 南京 className:中班classNum:12 addr: 南京 className:中班classNum:12
结论:
1、编译器自动生成的合成拷贝构造函数是浅拷贝
代码:
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); // 获取classname int getClassNum(); // 获取classNum void setAddr(const char* addr); // 修改addr void descrirition(); // 打印对象描述信息 Cls(const Cls& other); // 深浅拷贝 Cls(); // 自定义默认构造函数:没有返回值和类名相同 Cls(int classNum, string className, const char* addr); // 自定义参数构造函数 Cls(int classNum, string className); // 自定义参数构造函数重载 private: // 保护类内属性 string className; char* addr = NULL; int classNum; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } void Cls::setAddr(const char* addr) { strcpy_s(this->addr, 20, addr); } // 自定义默认构造函数来进行对象初始化 Cls::Cls() { cout << "自定义默认构造函数被调用" << endl; className = "小班"; addr = NULL; classNum = 11; } void Cls::descrirition() { cout << "addr: " << addr << " className:" << className << "classNum:" << classNum << endl; } // 自定义参数构造函数 Cls::Cls(int classNum, string className,const char* addr) { cout << "自定义参数构造函数-重载1" << endl; this->classNum = classNum; this->className = className; this->addr = new char[20]; strcpy_s(this->addr, 20, addr); } // 自定义参数构造函数重载 Cls::Cls(int classNum, string className) { cout << "自定义参数构造函数-重载2" << endl; this->classNum = classNum; this->className = className; } // 浅拷贝 Cls::Cls(const Cls& other) { cout << "浅拷贝" << endl; className = other.className; classNum = other.classNum addr = other.addr; } 深拷贝 //Cls::Cls(const Cls& other) { // 注意这里一定要在堆区重新开辟空间 // className = other.className; // classNum = other.classNum // addr = new char[20]; // strcpy_s(addr, 20, other.addr); //} int main() { Cls c1(12, "中班", "北京"); // 使用已创建的对象来创建对象调用,拷贝构造函数 Cls c2 = c1; Cls c3(c1); c1.descrirition(); c2.descrirition(); cout << "修改" << endl; c1.setAddr("南京"); c1.descrirition(); c2.descrirition(); system("pause"); return 0; }
输入、输出:
自定义参数构造函数-重载1 浅拷贝 浅拷贝 addr: 北京 className:中班classNum:12 addr: 北京 className:classNum:0 修改 addr: 南京 className:中班classNum:12 addr: 南京 className:classNum:0拷贝构造函数的调用时间
1、利用已有的对象构建新的对象
2、对象作为函数的形参,并且不是引用
3、对象作为函数返回值,并且不是引用
4、对象作为数组成员
代码:
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); // 获取classname int getClassNum(); // 获取classNum void setAddr(const char* addr); // 修改addr void descrirition(); // 打印对象描述信息 Cls(const Cls& other); // 深浅拷贝 Cls(); // 自定义默认构造函数:没有返回值和类名相同 Cls(int classNum, string className, const char* addr); // 自定义参数构造函数 Cls(int classNum, string className); // 自定义参数构造函数重载 private: // 保护类内属性 string className; char* addr = NULL; int classNum; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } void Cls::setAddr(const char* addr) { strcpy_s(this->addr, 20, addr); } // 自定义默认构造函数来进行对象初始化 Cls::Cls() { cout << "自定义默认构造函数被调用" << endl; className = "小班"; addr = NULL; classNum = 11; } void Cls::descrirition() { cout << "addr: " << addr << " className:" << className << "classNum:" << classNum << endl; } // 自定义参数构造函数 Cls::Cls(int classNum, string className,const char* addr) { cout << "自定义参数构造函数-重载1" << endl; this->classNum = classNum; this->className = className; this->addr = new char[20]; strcpy_s(this->addr, 20, addr); } // 自定义参数构造函数重载 Cls::Cls(int classNum, string className) { cout << "自定义参数构造函数-重载2" << endl; this->classNum = classNum; this->className = className; } // 浅拷贝 //Cls::Cls(const Cls& other) { // cout << "浅拷贝" << endl; // className = other.className; // classNum = other.classNum; // addr = other.addr; //} // 深拷贝 Cls::Cls(const Cls& other) { cout << "深拷贝" << endl; className = other.className; classNum = other.classNum; // 注意这里一定要重新在堆区创建空间 addr = new char[20]; strcpy_s(addr, 20, other.addr); } // 对象作为函数参数 void getMeag(Cls c) { c.descrirition(); } // 对象作为函数返回值 Cls clsReturn(Cls& c1, Cls& c2) { if (c1.getClassNum() >= c2.getClassNum()) { return c1; } else return c2; } int main() { Cls c1(12, "中班", "北京"); // 1、使用已创建的对象来创建对象调用拷贝构造函数 Cls c2 = c1; Cls c3(c1); c1.descrirition(); c2.descrirition(); cout << "修改" << endl; c1.setAddr("南京"); c1.descrirition(); c2.descrirition(); // 2、作为函数形参 getMeag(c1); // 3、作为函数返回值 clsReturn(c1, c2); //4、作为数组成员 Cls C3[3] = {c1, c2, c3}; // C3[0]=c1 ....C3[2]=c3 system("pause"); return 0; }
输入、输出:
自定义参数构造函数-重载1 深拷贝 深拷贝 addr: 北京 className:中班classNum:12 addr: 北京 className:中班classNum:12 修改 addr: 南京 className:中班classNum:12 addr: 北京 className:中班classNum:12 深拷贝 addr: 南京 className:中班classNum:12 深拷贝 深拷贝 深拷贝 深拷贝
总结:
1、四种拷贝构造函数被调用时间
2、深浅拷贝
3、对象作为函数返回值和参数的时候,如果不是引用。那么会拷贝一份对象,占用内存空间。
对象创建完毕以后出现对象和对象赋值,会调用赋值构造函数
代码:
#include#include #include using namespace std; // 类声明 class Cls { public: string getClassName(); // 获取classname int getClassNum(); // 获取classNum void setAddr(const char* addr); // 修改addr void descrirition(); // 打印对象描述信息 Cls(const Cls& other); // 深浅拷贝 Cls(); // 自定义默认构造函数:没有返回值和类名相同 Cls(int classNum, string className, const char* addr); // 自定义参数构造函数 Cls(int classNum, string className); // 自定义参数构造函数重载 Cls& operator=(const Cls& other); // 赋值构造函数 private: // 保护类内属性 string className; char* addr = NULL; int classNum; }; // 类内成员函数定义 string Cls::getClassName() { return className; } int Cls::getClassNum() { return classNum; } void Cls::setAddr(const char* addr) { strcpy_s(this->addr, 20, addr); } // 自定义默认构造函数来进行对象初始化 Cls::Cls() { cout << "自定义默认构造函数被调用" << endl; className = "小班"; addr = new char[20]; classNum = 11; } void Cls::descrirition() { cout << "addr: " << addr << " className:" << className << "classNum:" << classNum << endl; } // 自定义参数构造函数 Cls::Cls(int classNum, string className,const char* addr) { cout << "自定义参数构造函数-重载1" << endl; this->classNum = classNum; this->className = className; this->addr = new char[20]; strcpy_s(this->addr, 20, addr); } // 自定义参数构造函数重载 Cls::Cls(int classNum, string className) { cout << "自定义参数构造函数-重载2" << endl; this->classNum = classNum; this->className = className; } // 赋值拷贝构造函数 Cls& Cls::operator=(const Cls& other) { cout << "赋值拷贝构造函数" << endl; // 防止出现c1 = c1; if (this == &other) { return *this; } className = other.className; classNum = other.classNum; return *this; // 链式编程 c1 = c2 = c3; } int main() { Cls c1, c2; c2 = c1; system("pause"); return 0; }
输入、输出:
自定义默认构造函数被调用 自定义默认构造函数被调用 赋值拷贝构造函数



