博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
04.构造函数 析构函数 拷贝函数
阅读量:6418 次
发布时间:2019-06-23

本文共 9290 字,大约阅读时间需要 30 分钟。

(创建于2017/12/24)

构造函数的调用
#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Me {public:    Me() {        cout << "无参构造"<< endl;    }    Me(int a) {        cout << "有参构造" <<< endl;    }    Me(const Me &me) {        cout << "拷贝构造函数"<< endl;    }};int main() {    //调用无参构造    Me me;    //调用有参构造第一种方式-括号法    Me me2(1);    //调用有参构造第2种方式-等号法    Me me3 = (2);    //调用有参构造第3种方式    Me m4 = Me(3);    system("pause");    return 0;}
拷贝构造函数的调用
#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    Class2() {        cout << "class2构造函数" << endl;    }    Class2(const Class2 &clazz) {        cout << "class2拷贝构造函数"<< endl;    }};int main() {    Class2 class_a;    //用一个对象初始化另一个对象的时候,拷贝构造函数被编译器调用,    //如果我们不提供显示的拷贝构造函数,编译器会调用默认的    Class2 class_b = class_a;    system("pause");    return 0;}
拷贝构造函数和析构函数
#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    Class2() {        cout << "class2构造函数" << endl;    }    Class2(const Class2 &clazz) {        cout << "class2拷贝构造函数"<< endl;    }    ~Class2() {        cout << "class2的析构函数"<< endl;    }};void begin2(Class2 &clas) {    cout << "begin2"<< endl;}void begin3(Class2 clas) {    cout << "begin3" << endl;}void begin() {    Class2 class_a;    Class2 class_b = class_a;    begin2(class_b);    cout << "--------------------------" << endl;    begin3(class_b);}int main() {    begin();    system("pause");    return 0;}打印结果class2构造函数             //Class2 class_aclass2拷贝构造函数      //Class2 class_b = class_a;begin2                           //cout << "begin2"<< endl;    begin2传递的是引用,没有执行拷贝构造函数--------------------------class2拷贝构造函数      //begin3传递的是对象,直接赋值,拷贝构造函数执行begin3class2的析构函数class2的析构函数class2的析构函数请按任意键继续. . .
匿名对象的拷贝和析构

调用get方法,创建了一个Class2对象,并将它返回,此时看打印结果,构造函数执行一次在意料之中,但是为什么拷贝构造函数也会执行,而且析构函数执行了两次,可见这个过程中产生了两个对象。原因在于,函数的返回值是一个元素(对象)的时候,返回的是一个新的匿名对象,而不是真的像get方法中把a返回了,相当于把a赋值给了一个匿名对象,所以拷贝构造函数被调用了一次,产生两个对象,所以销毁两次。

#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    Class2() {        cout << "class2构造函数" << endl;    }    Class2(const Class2 &clazz) {        cout << "class2拷贝构造函数"<< endl;    }    ~Class2() {        cout << "class2的析构函数"<< endl;    }};Class2 get() {    Class2 a;    return a;}int main() {    get();    system("pause");    return 0;}打印结果class2构造函数class2拷贝构造函数class2的析构函数class2的析构函数请按任意键继续. . .

然后我们在上边的代码基础上做一点改动,get产生的对象被接收。此时看打印,析构函数只执行了一次。拷贝构造函数执行,将产生的匿名对象通过=号赋值给temp,因为这个新的对象被temp接收,那么get方法执行完成,这个对象没有被销毁,销毁的是a对象

#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    Class2() {        cout << "class2构造函数" << endl;    }    Class2(const Class2 &clazz) {        cout << "class2拷贝构造函数"<< endl;    }    ~Class2() {        cout << "class2的析构函数"<< endl;    }};Class2 get() {    Class2 a;    return a;}int main() {    Class2 temp = get();    system("pause");    return 0;}打印结果class2构造函数class2拷贝构造函数class2的析构函数请按任意键继续. . .

在上边代码上再做一点改动,我们把temp先初始化,然后接收get产生的对象.可以看到析构函数又执行了两次,这是因为,get产生的新对象是用于初始化了另一个已经存在的对象,然后这个匿名对象就没有用了,会被析构掉,temp已经分配了内存,有了自己的空间,将get通过=号赋值给它只是将get对象的内容拷贝到了temp上,然后get产生对象的空间就没有用了,被释放,而为什么上边的temp没有初始化情况下,get产生的对象不会被析构,因为上边temp只是定义了一个对象,还没有分配空间,接收get对象后相当于指向了这块空间,这块空间有了引用就不会被释放,跟Java垃圾回收机制很像

#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    Class2(int a, int b) {    }    Class2() {        cout << "class2构造函数" << endl;    }    Class2(const Class2 &clazz) {        cout << "class2拷贝构造函数"<< endl;    }    ~Class2() {        cout << "class2的析构函数"<< endl;    }};Class2 get() {    Class2 a;    return a;}int main() {    Class2 temp(1,2);    temp = get();    system("pause");    return 0;}打印结果class2构造函数class2拷贝构造函数class2的析构函数class2的析构函数请按任意键继续. . .
浅拷贝存在的问题

C++默认提供的拷贝构造函数在进行拷贝的时候是浅拷贝,对于对象或者说内存中的空间,它拷贝的是地址而不是重新开辟空间,这会导致一些列的问题。下边的程序就是因为浅拷贝导致同一个内存空间被free两次而导致崩溃

#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    char *p;public:    Class2(const char *name) {        int len = strlen(name);        p = (char *)malloc(len + 1);        strcpy(p, name);        cout <<"执行函数"<
<< endl; } ~Class2() { cout << "class2的析构函数"<< endl; if (p != NULL) { free(p); p = NULL; } }};void get() { //有参构造执行,开辟一段空间存放ren这个字符串 Class2 a("ren"); //默认拷贝函数执行,通过a浅拷贝得到一份b,对于成员变量p,仅仅是 //定义了一个指针指向了和a同样的内存空间,那么此时,get执行 //完成,开始执行析构函数,先析构b,判断p不等于p满足free掉p //指向的空间,然后开始析构a,因为两个对象中的p变量不是同一个变量 //那么此时p!=NULL仍然是成立的,但是由于二者指向同一份内存空间 //导致free了两次同一个空间,所以报错 Class2 b = a;}int main() { get(); system("pause"); return 0;}

那么浅拷贝问题如何解决?只需要我们手动的编写拷贝构造函数,单独开辟空间即可

#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class Class2 {public:    char *p;public:    Class2(const char *name) {        int len = strlen(name);        p = (char *)malloc(len + 1);        strcpy(p, name);        cout <<"执行函数"<
<< endl; } //显示的编写拷贝构造函数,重新开辟内存保存字符串,避免指向同一个空间 Class2(const Class2 &clazz) { p = (char *)malloc(100); strcpy(p, clazz.p); } ~Class2() { cout << "class2的析构函数"<< endl; if (p != NULL) { free(p); p = NULL; } }};void get() { //有参构造执行,开辟一段空间存放ren这个字符串 Class2 a("ren"); //默认拷贝函数执行,通过a浅拷贝得到一份b,对于成员变量p,仅仅是 //定义了一个指针指向了和a同样的内存空间,那么此时,get执行 //完成,开始执行析构函数,先析构b,判断p不等于p满足free掉p //指向的空间,然后开始析构a,因为两个对象中的p变量不是同一个变量 //那么此时p!=NULL仍然是成立的,但是由于二者指向同一份内存空间 //导致free了两次同一个空间,所以报错 Class2 b = a;}int main() { get(); system("pause"); return 0;}
构造参数列表

执行顺序,像这种一个类中又套了另一个类,而被嵌套的类又只提供了有参构造,就需要通过构造参数列表对他进行初始化,先执行被组合对象的构造函数,如果组合对象有多个,则按照定义顺序执行构造函数,比如下边,先执行a构造,在执行a2构造,在下边的程序中就是先执行A的构造,然后执行外层B的构造,而析构函数则和构造函数调用顺序相反

#define  _CRT_SECURE_NO_WARNINGS#include "iostream"  //包含c++的头文件using namespace std;class A {public:    A(int a) {    }};class B {public:    int b;    A a;    A a2;    B(int b):a(1),a2(2){    }    B(int a, int b, int c, int d) :a(c), a2(d) {    }};int main() {    system("pause");    return 0;}

C++类的一般写法

.h 头文件声明:

#pragma once  //防止重复循环引用class MyTeacher{public:    int age;     char*name;public :    void setAge(int age);    int getAge();    void setName(char *name);    char *getName();};

.cpp源文件定义

#include "MyTeacher.h"#include
//这个头文件和命名空间有一个不存在 cout就无法使用using namespace std;void MyTeacher::setAge(int age){ this->age = age;}int MyTeacher::getAge(){ return this->age;}void MyTeacher::setName(char *name){ this->name = name;}char *MyTeacher::getName(){ return this->name;}void main(){ MyTeacher t1; t1.name = "renzhenming"; t1.age = 26; cout << t1.getName()<< endl; system("pause");}

构造函数 析构函数 拷贝函数

#define _CRT_SECURE_NO_WARNINGS#include
//这个头文件和命名空间有一个不存在 cout就无法使用using namespace std;class MyTeacher{public: int age; char*name;public: MyTeacher() { this->name = (char*)malloc(100); strcpy(name, "renzhenming"); age = 26; cout << "无参构造函数" << this->name << endl; } MyTeacher(char *name, int age) { //有参构造函数会覆盖默认的无参构造,同Java this->age = age; this->name = (char*)malloc(100); strcpy(this->name, name); cout << "有参构造函数" << this->name<
name); //C++的释放方法 free(this->name); //C的释放方法 cout << "析构函数" << endl; } //浅拷贝 /*MyTeacher(const MyTeacher &obj) { //默认的拷贝构造函数就是这样,是值拷贝,属于浅拷贝 this->name = obj.name; this->age = obj.age; cout << "拷贝构造函数" << this->name << endl; }*/ //深拷贝(复写默认的拷贝函数) //使用深拷贝可以避免浅拷贝的问题,拷贝函数的时候重新开辟空间存放name值,这样,释放空间的时候就会 //避免一个内存释放两次的问题, //浅拷贝(值拷贝),拷贝的是指针的地址 //深拷贝,拷贝的是指针指向的内容 //拷贝构造函数何时会调用? //1.声明时赋值 //MyTeacher t2 = t1; //2.作为参数传入,实参给形参赋值(都是这种变形:MyTeacher t2 = t1;) //func1(t1); //3.作为函数返回值返回,给变量初始化赋值 //MyTeacher t3 = func1(t1); MyTeacher(const MyTeacher &obj) { //复制name属性 int len = strlen(obj.name); this->name = (char*)malloc(len + 1);//+1是为了结束符 0 strcpy(this->name, obj.name); this->age = obj.age; cout << "拷贝构造函数" << this->name << endl; } void printinfo() { cout << name << "," << age << endl; }};void func() { MyTeacher t; //MyTeacher t("a",1);}MyTeacher func1(MyTeacher t) { t.printinfo(); return t;}void func2() { //测试浅拷贝存在的问题 //执行这段代码后,有参构造执行,申请一块空间给name存放传入的name, MyTeacher t1("什么问题", 11); //执行这段代码后,默认的拷贝函数执行,进行值的拷贝,t2的name也指向了开辟的存放name的那块空间 //此时,t1的name和t2的name指向了同一块空间 MyTeacher t2 = t1; t2.printinfo(); //这个func2函数执行完成之后,回收两个变量,回收t1的时候,析构函数执行,free了t1中的name,回收 //t2的时候,析构函数同样执行,回收name,因为t2的name同样指向那块空间,所以导致那块空间被回收两次,就报错了}void main(){ cout << "-------------构造函数的调用---------------" << endl; //调用无参构造函数 MyTeacher at; //调用有参构造函数 MyTeacher t("renzhenming",26); cout << "-------------析构函数在函数执行完成之后需要回收的时候调用---------------" << endl; func(); cout << "-------------构造函数的另一种调用方式---------------" << endl; MyTeacher t2 = MyTeacher("zhangsna", 22); cout << "-------------拷贝构造函数---------------" << endl; MyTeacher t3("lisi",21); MyTeacher t4 = t3; t4.printinfo(); cout << "-------------浅拷贝(默认的值拷贝)存在的问题---------------" << endl; func2(); system("pause");}

转载地址:http://ozvra.baihongyu.com/

你可能感兴趣的文章
大型机、小型机、x86服务器的区别
查看>>
J2EE十三个规范小结
查看>>
算法(第四版)C#题解——2.1
查看>>
网关支付、银联代扣通道、快捷支付、银行卡支付分别是怎么样进行支付的?...
查看>>
大数据开发实战:Stream SQL实时开发一
查看>>
C++返回引用的函数例程
查看>>
dll 问题 (转)
查看>>
使用sql生成UUID
查看>>
mysql日期函数(转)
查看>>
REST API用得也痛苦
查看>>
test for windows live writer plugins
查看>>
Tiny210 U-BOOT(二)----配置时钟频率基本原理
查看>>
读javascript高级程序设计14-错误处理与调试
查看>>
代理模式
查看>>
javaweb学习总结(二十四)——jsp传统标签开发
查看>>
让script的type属性等于text/html
查看>>
[Docker] Docker Machine intro
查看>>
HA 高可用软件系统保养指南
查看>>
linux 文件系统sysvinit 流程分析
查看>>
体素科技:2018年,算法驱动下的医学影像分析进展
查看>>