1.构造函数
类的初始化即为构造函数。也为:隐式的初始化。
构造函数在对象初始化的时候,自动被调用。隐式的调用。
构造函数分为三种:有参构造函数、无参构造函数、拷贝构造函数。
有参构造函数调用有三种:括号法、等号法、手工法。
- #include <iostream>
- using 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");
- }
2.析构函数
析构函数(destructor) 与
构造函数
相反,当
对象
脱离其
作用域
时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立
对象
时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
主函数结束的同时,对象stud1,stud2均应被“清理”,而清理就是通过调用了析构函数实现的。
- #define _CRT_SECURE_NO_WARNINGS
- #include<string>
- #include<iostream>
- 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;
- }
3.拷贝构造函数
拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。
当我们没有编写拷贝构造函数的时候,c++编译器会默认给我们提供一个拷贝构造函数,执行的是浅拷贝。
copy构造函数四种应用场景;
第一种场景:=
- #include <iostream>
- using 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;
- }
第二种场景:()
- #include <iostream>
- using 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;
- }
第三种场景:对象以值传递的方式传入函数参数
- #include <iostream>
- using 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 <iostream>
- 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;
- }
4.深copy浅copy
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
- #include "iostream"
- using namespace std;
- class name
- {
- public :
- name(charchar *pn) ;
- name( name &obj)
- {
- cout <<" copy Constructing " << endl ;
- charchar *pn = obj.getPn();
- pname = (charchar *)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 :
- charchar *pname ; int size ;
- public:
- charchar * getPn()
- {
- return pname;
- }
- void operator=(name &obj1)
- {
- cout <<" 执行=操作" << endl ;
- charchar *pn = obj1.getPn();
- pname = (charchar *)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(charchar *pn)
- {
- cout <<" Constructing " << pn << endl ;
- pname = (charchar *)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<<obj2.getPn()<<endl;
- }
- void main()
- {
- playmain();
- system("pause");
- }
- #define _CRT_SECURE_NO_WARNINGS
- #include "iostream"
- using namespace std;
- class name
- {
- public:
- name(charchar *pn);
- name(name &obj)
- {
- cout << " copy Constructing " << endl;
- charchar *pn = obj.getPn();
- pname = (charchar *)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:
- charchar *pname; int size;
- public:
- charchar * getPn()
- {
- return pname;
- }
- void operator=(name &obj1)
- {
- cout << " 执行=操作" << endl;
- if (pname != NULL)//此处有一个疑问:如果不free, 直接将原来的内存进行重新赋值
- {
- charchar *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(charchar *pn)
- {
- cout << " Constructing " << pn << endl;
- pname = (charchar *)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;
- }
最终分析图:
转自 http://blog.csdn.net/waldmer/article/details/43051757