本文共 7048 字,大约阅读时间需要 23 分钟。
类的初始化即为构造函数。也为:隐式的初始化。
构造函数在对象初始化的时候,自动被调用。隐式的调用。
构造函数分为三种:有参构造函数、无参构造函数、拷贝构造函数。
有参构造函数调用有三种:括号法、等号法、手工法。
#includeusing namespace std;class Test{private: int m_a;public: Test()//无参构造函数 { } Test(const Test &obj)//拷贝构造函数 { } Test(int a)//有参构造函数 { m_a = a; } void print() { cout << "m_a:" << m_a << endl; } };void main(){ Test t1(10);//括号法 //c++编译器自动调用这个类的有参构造函数 t1.print(); Test t2 = 20;//等号法 //c++编译器自动调用这个类的有参构造函数 t2.print(); Test t3 = Test(30);//手工法 //程序员手工的调用构造函数 进行对象初始化 t3.print(); system("pause");}
#define _CRT_SECURE_NO_WARNINGS#include#include using namespace std;class stud//声明一个类{private://私有部分 int num; char name[10]; char sex;public://公用部分 stud(int n, char nam[], char s)//构造函数 { num = n; strcpy(name, nam); sex = s; } ~stud()//析构函数 { cout << "stud has been destructed!" << endl;//通过输出提示告诉我们析构函数确实被调用了 } void display()//成员函数 { cout << "num:" << num << endl; cout << "name:" << name << endl; cout << "sex:" << sex << endl; }};int main(){ stud stud1(10010, "Wang-li", 'f'); stud stud2(10011, "Zhang-fun", 'm');//建立两个对象 stud1.display();//输出学生1的数据 stud2.display();//输出学生2的数据 system("pause"); return 0;}
拷贝构造函数,是一种特殊的构造函数,它由调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在时用户定义类型的值传递及返回。拷贝构造函数要调用的拷贝构造函数和成员函数。如果可以的话,它将用方式调用,另外,也可以用非常量方式调用。
当我们没有编写拷贝构造函数的时候,c++编译器会默认给我们提供一个拷贝构造函数,执行的是浅拷贝。
copy构造函数四种应用场景;
#includeusing namespace std;class CExample {private: int a;public: //构造函数 CExample(int b) { a = b; } //拷贝构造函数 CExample(const CExample& C) { a = C.a; } //一般函数 void Show() { cout << a << endl; }};int main(){ CExample A(100); CExample B = A; //注意这里的对象初始化要调用拷贝构造函数,而非赋值 // CExample B(A); 也是一样的 B.Show(); return 0;}
#includeusing namespace std;class CExample {private: int a;public: //构造函数 CExample(int b) { a = b; } //拷贝构造函数 CExample(const CExample& C) { a = C.a; } //一般函数 void Show() { cout << a << endl; }};int main(){ CExample A(100); //CExample B = A; //注意这里的对象初始化要调用拷贝构造函数,而非赋值 CExample B(A); //也是一样的 B.Show(); return 0;}
#includeusing namespace std;class CExample{private: int a;public: //构造函数 CExample(int b) { a = b; cout << "creat: " << a << endl; } //拷贝构造 CExample(const CExample& C) { a = C.a; cout << "copy" << endl; } //析构函数 ~CExample() { cout << "delete: " << a << endl; } void Show() { cout << a << endl; }};//全局函数,传入的是对象 void g_Fun(CExample C){ cout << "test" << endl;}int main(){ CExample test(1); //传入对象 g_Fun(test); return 0;}
#include添加断点,逐条语句运行,观察程序的执行步骤以及打印输出:using namespace std;class CExample{private: int a;public: //构造函数 CExample(int b=0) { a = b; cout << "a:" << a << endl; } ~CExample() { cout << "destroy a:" << a << endl; } //拷贝构造 CExample(const CExample& C) { a = C.a; cout << "copy a:"<< a << endl; }};//全局函数 CExample g_Fun(){ CExample temp(10); return temp;}int main(){ CExample ret; ret = g_Fun(); return 0;}
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
#include "iostream"using namespace std;class name{ public : name(char *pn) ; name( name &obj) { cout <<" copy Constructing " << endl ; char *pn = obj.getPn(); pname = (char *)malloc(strlen(pn) +1); if (pname!=NULL) strcpy(pname,pn) ; //pname = new char[strlen(pn)+1] ; //if (pname!=0) strcpy(pname,pn) ; size = strlen(pn) ; } ~ name() ;protected : char *pname ; int size ;public: char * getPn() { return pname; } void operator=(name &obj1) { cout <<" 执行=操作" << endl ; char *pn = obj1.getPn(); pname = (char *)malloc(strlen(pn) +1);//此处malloc了内存,没有free,存在一个潜在的bug if (pname!=NULL) strcpy(pname,pn) ; //pname = new char[strlen(pn)+1] ; //if (pname!=0) strcpy(pname,pn) ; pname[0] = 'm'; size = strlen(pn) ; }} ;name::name(char *pn){ cout <<" Constructing " << pn << endl ; pname = (char *)malloc(strlen(pn) +1); if (pname!=0) strcpy(pname,pn) ; //pname = new char[strlen(pn)+1] ; //if (pname!=0) strcpy(pname,pn) ; size = strlen(pn) ;} name :: ~ name(){ cout << " Destructing " << pname << endl ; pname[0] = '\0' ; //delete []pname ; free(pname); size = 0 ;}void playmain(){ name obj1("name1"); //如果你不写copy构造函数,那么C++编译器会给我们提供一个默认的copy构造函数 (浅cpy) name obj2 = obj1; //如果你不写=操作,那么C++编译器会给我们提供一个=操作函数 (浅cpy) obj2 = obj1; cout<<
#define _CRT_SECURE_NO_WARNINGS#include "iostream"using namespace std;class name{public: name(char *pn); name(name &obj) { cout << " copy Constructing " << endl; char *pn = obj.getPn(); pname = (char *)malloc(strlen(pn) + 1); if (pname != NULL) strcpy(pname, pn); //pname = new char[strlen(pn)+1] ; //if (pname!=0) strcpy(pname,pn) ; size = strlen(pn); } ~name();protected: char *pname; int size;public: char * getPn() { return pname; } void operator=(name &obj1) { cout << " 执行=操作" << endl; if (pname != NULL)//此处有一个疑问:如果不free, 直接将原来的内存进行重新赋值 { char *pn = obj1.getPn(); strcpy(pname, pn); pname[0] = 'N'; size = strlen(pn); } } /* void operator=(name &obj1) { cout <<" 执行=操作" << endl ; if (pname != NULL)//此处有一个疑问:如果不free, 直接将原来的内存进行重新赋值 { free(pname); pname = NULL; size = 0; } char *pn = obj1.getPn(); pname = (char *)malloc(strlen(pn) +1); if (pname!=NULL) strcpy(pname,pn) ; //pname = new char[strlen(pn)+1] ; //if (pname!=0) strcpy(pname,pn) ; pname[0] = 'm'; size = strlen(pn) ; } */};name::name(char *pn){ cout << " Constructing " << pn << endl; pname = (char *)malloc(strlen(pn) + 1); if (pname != 0) strcpy(pname, pn); //pname = new char[strlen(pn)+1] ; //if (pname!=0) strcpy(pname,pn) ; size = strlen(pn);}name :: ~name(){ cout << " Destructing " << pname << endl; pname[0] = '\0'; //delete []pname ; free(pname); size = 0;}int playmain(){ name obj1("name1"); name obj3("name3"); //如果你不写copy构造函数,那么C++编译器会给我们提供一个默认的copy构造函数 (浅cpy) name obj2 = obj1; //做业务逻辑 //此处省略500行 //如果你不写=操作,那么C++编译器会给我们提供一个=操作函数 (浅cpy) //会调用对象2 的=号操作函数, obj3是形参, obj2干什么去了? obj2 = obj3; cout << obj2.getPn() << endl; return 0;}int main(){ playmain(); //system("pause"); return 0;}
最终分析图: