一:补充---无参构造函数(默认无参构造函数)在实例化对象时注意点

(一)若没有写构造函数,则类会含有一个默认无参构造函数

(二)若自定义一个构造函数,则类不会提供默认构造函数

class A
{
public:
A(int a)
{
cout << "有参构造函数" << endl;
} void getInfo()
{
cout << "对象构造完毕" << endl;
}
};

(三)重点:实例化对象时C++允许使用 类名 对象(构造参数)  但是对于无参构造时是无法使用的

class A
{
public:
A()
{
cout << "无参构造函数" << endl;
} A(int a)
{
cout << "有参构造函数" << endl;
} void getInfo()
{
cout << "对象构造完毕" << endl;
}
}; void main()
{
A a(); //warning C4930: “A a(void)”: 未调用原型函数(是否是有意用变量定义的?)
}
会认为该语句表示声明一个名为a的函数,返回类型是A。

所以调用无参构造函数可以使用:
A* a=new A();
a->getInfo();

二:补充---默认拷贝构造函数

当类中没有定义拷贝构造函数时,编译器默认提供一个默认拷贝构造函数,简单的进行成员变量的值复制(属于浅拷贝)

三:浅拷贝(默认构造函数)以及对应深拷贝

默认拷贝构造函数只能完成成员值的简单的复制
若是类中含有指针成员,在堆上面开辟内存,默认拷贝构造函数,只会做指针值的复制。会导致内存存取错误。

(一)默认构造函数演示错误产生:第一个对象析构后将堆内存回收,而第二个对象指针依旧指向那块回收的内存。导致读取失败

class A
{
private:
char* pName;
public:
A()
{
cout << "A无参构造函数" << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + 1);  //堆上开辟内存
strcpy(pName, name);
} ~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
delete[] pName;  //进行析构时释放内存
} void getInfo()
{
cout << "Name:" << pName << endl;
}
}; void main()
{
A* a=new A("ld");
A b(*a); //会调用默认构造函数(浅拷贝) a->getInfo();
b.getInfo(); delete a; b.getInfo(); system("pause");
}

(二)进行深拷贝处理(自定义拷贝构造函数)

class A
{
private:
char* pName;
public:
A()
{
cout << "A无参构造函数" << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name);
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + 1); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName);
}
~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
delete[] pName;
} void getInfo()
{
cout << "Name:" << pName << endl;
}
}; void test()
{
A* a = new A("ld");
A b(*a); //=不同于拷贝构造函数 a->getInfo();
b.getInfo(); delete a;  //释放a对象,会调用析构 b.getInfo();
}  //在函数结尾后释放b对象,调用析构释放内存 void main()
{
test();  //进行测试 system("pause");
}

四:浅拷贝(=运算符)以及对应深拷贝

(一)=运算和拷贝构造函数不相关:若是不进行=操作重载,默认是进行浅拷贝

class A
{
private:
char* pName;
public:
A()
{
cout << "A无参构造函数" << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name);
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName);
}
~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
delete[] pName;
} void getInfo()
{
cout << "Name:" << pName << endl;
}
}; void test()
{
A a("ld");
A b; //若是A b=a;会调用拷贝构造函数
b = a; //会使用=操作符,由于没有重载该运算符,所以是浅拷贝

} void main()
{
test(); system("pause");
}

(二)注意点: A b = a;  调用的是拷贝构造函数  A b;  b=a;调用的是重载运算符=

(三)重载=运算符,实现深拷贝

    A& operator=(A& a)
{
cout << "调用重载运算符进行深拷贝" << endl;
this->pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(this->pName, a.pName);
return *this;
}

五:补充---不存在类的类型变量声明  A a;不是声明,是产生一个对象a,调用无参构造函数

(一)演示一:A a会调用无参构造函数

class A
{
private:
char* pName;
public:
A()
{
cout << "A无参构造函数" << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name);
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName);
} ~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
delete[] pName;
}
}; void test()
{
cout << "" << endl;
A b;
cout << "" << endl;
}

(二)演示二:若不存在无参构造函数,则出错(自己写了其他构造函数)

class A
{
private:
char* pName;
public:
A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name);
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName);
} ~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
delete[] pName;
}
};

六:补充---匿名对象的去和留

(一)若是将返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构

1.首次演示:含有一个错误

class A
{
private:
char* pName;
public:
A()
{
cout << "无参构造函数" << endl;
pName = NULL;
cout << this << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name); cout << this << endl;
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName); cout << this << endl;
} void getInfo()
{
if (pName != NULL)
{
cout << pName << endl;
}
else
{
cout << "no name" << endl;
}
} ~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
this->pName;
cout << this << endl;
if (pName != NULL)
{
delete[] pName;
}
}
}; A getNonObj()
{
A a("da");
//a.getInfo();
return a;
} void test()
{
A b; //同类型对象
b = getNonObj(); //getNonObj返回一个对象,赋值给另外一个同类型的对象b 这是赋值 =默认是使用浅拷贝 若是需要使用深拷贝,则要重载=运算符
}  //在这里进行析构时,会报错 void main()
{
test();
system("pause");
}

2.原因分析《重点》

从test方法开始:
这个程序一共生成3个对象,
1.在A b这里生成一个无参对象 A1
2.在getNonObj()方法生成一个 A2 ,然后生成一个拷贝构造对象 A3 赋值给b
3.在getNonObj()最后析构局部对象 A2
4.进入test方法最后,按照局部函数入栈顺序,将2中的拷贝构造对象出栈进行析构 A3
5.还剩下最后一个A b最开始的无参对象,会进行析构 A1--->但是这里会报错
原因:
最开始A1 中pName为NULL,进行b = getNonObj()将b赋值为A3,是浅拷贝,而不是深拷贝
所以会使A1和A3指向同一个内存,而A3析构时,已经进行内存释放,所以后面A1就会出错
解决方法:
重载运算符=

3.正确实现:进行=运算符重载

class A
{
private:
char* pName;
public:
A()
{
cout << "无参构造函数" << endl;
pName = NULL;
cout << this << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name); cout << this << endl;
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName); cout << this << endl;
} A& operator=(const A &a)
{
cout << "调用=运算符重载进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName); cout << this << endl;
return *this;
} void getInfo()
{
if (pName != NULL)
{
cout << pName << endl;
}
else
{
cout << "no name" << endl;
}
} ~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
this->pName;
cout << this << endl;
if (pName != NULL)
{
delete[] pName;
}
}
}; A getNonObj()
{
A a("da");
//a.getInfo();
return a;
} void test()
{
A b; //同类型对象
b = getNonObj(); //getNonObj返回一个匿名对象,赋值给另外一个同类型的对象b } void main()
{
test();
system("pause");
}

进行=运算符重载

(二)若是将返回的匿名对象,来初始化另外一个同类型的对象,那么匿名对象会直接进行拷贝构造对象转成新的对象

class A
{
private:
char* pName;
public:
A()
{
cout << "无参构造函数" << endl;
pName = NULL;
cout << this << endl;
} A(char* name)
{
cout << "有参构造函数" << endl;
pName = (char*)malloc(strlen(name) + );
strcpy(pName, name); cout << this << endl;
} A(const A& a)
{
cout << "调用自定义拷贝构造函数进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName); cout << this << endl;
} A& operator=(const A &a)
{
cout << "调用=运算符重载进行深拷贝" << endl;
pName = (char*)malloc(strlen(a.pName) + ); //私有是类间私有,这是同一个类,故可直接使用pName
strcpy(pName, a.pName); cout << this << endl;
return *this;
} void getInfo()
{
if (pName != NULL)
{
cout << pName << endl;
}
else
{
cout << "no name" << endl;
}
} ~A()
{
cout << "调用析构函数,释放内存,习惯良好66" << endl;
this->pName;
cout << this << endl;
if (pName != NULL)
{
delete[] pName;
}
}
}; A getNonObj()
{
A a("da");
//a.getInfo();
return a;
} void test()
{
A b = getNonObj();//直接将匿名对象用来初始化同类型对象 会将拷贝构造函数直接设置为这个新的对象
} void main()
{
test();
system("pause");
}

七:总结--对拷贝构造函数和=操作符重载的区别

(一)A a = b; 进行初始化,会直接调用拷贝构造函数,不会去找=操作符重载

(二)A a;   //先生成一个无参对象     a=b;  //会进行赋值操作,调用=操作符重载方法

C++回顾day02---<拷贝构造函数:重点>的更多相关文章

  1. c++入门之—运算符重载和友元函数

    运算符重载的意义是:将常见的运算符重载出其他的含义:比如将*重载出指针的含义,将<<与cout联合使用重载出输出的含义,但需要认识到的问题是:运算符的重载:本质仍然是成员函数,即你可以认为 ...

  2. Swift教程之运算符重载

    http://blog.csdn.net/mengxiangyue/article/details/43437797 原文地址:http://www.raywenderlich.com/80818/o ...

  3. C++ 运算符重载时,将运算符两边对象交换问题.

    在C++进行运算符重载时, 一般来讲,运算符两边的对象的顺序是不能交换的. 比如下面的例子: #include <iostream> using namespace std; class ...

  4. C#高级编程笔记2016年10月12日 运算符重载

    1.运算符重载:运算符重重载的关键是在对象上不能总是只调用方法或属性,有时还需要做一些其他工作,例如,对数值进行相加.相乘或逻辑操作等.例如,语句if(a==b).对于类,这个语句在默认状态下会比较引 ...

  5. C++运算符重载

    C++运算符重载 基本知识 重载的运算符是具有特殊名字的函数,他们的名字由关键字operator和其后要定义的运算符号共同组成. 运算符可以重载为成员函数和非成员函数.当一个重载的运算符是成员函数时, ...

  6. 标准C++之运算符重载和虚表指针

    1 -> *运算符重载 //autoptr.cpp     #include<iostream> #include<string> using namespace std ...

  7. python运算符重载

    python运算符重载就是在解释器使用对象内置操作前,拦截该操作,使用自己写的重载方法. 重载方法:__init__为构造函数,__sub__为减法表达式 class Number: def __in ...

  8. PoEduo - C++阶段班【Po学校】-Lesson03-5_运算符重载- 第7天

    PoEduo - Lesson03-5_运算符重载- 第7天 复习前面的知识点 空类会自动生成哪些默认函数 6个默认函数    1  构造  2  析构   3  赋值  4 拷贝构造  5 oper ...

  9. 不可或缺 Windows Native (24) - C++: 运算符重载, 自定义类型转换

    [源码下载] 不可或缺 Windows Native (24) - C++: 运算符重载, 自定义类型转换 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 运算符重载 自 ...

  10. 我的c++学习(8)运算符重载和友元

    运算符的重载,实际是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该运算符时就调用此函数来行使运算符功能.这个函数叫做运算符重载函数(常为类的成员函数). 方法与解释 ◆ 1.定义运 ...

随机推荐

  1. 第二十二天 logging hashlib re 模块

    今日内容 logging功能完善的日志模块 re正则表达式模块主要处理字符串匹配 查找 搜索给你一个字符串 要从中找到你需要的东西 爬虫大量使用 hashlib hash算法相关的库 算法怎么算不需要 ...

  2. jsp小测试--猜大小

    page1.jpg: <%@ page language="java" import="java.util.*" pageEncoding="g ...

  3. BZOJ 2049 洞穴勘测

    LCT判断联通性 没什么特别的..还是一个普通的板子题,把LCT当并查集用了,只不过LCT灵活一些,还可以断边 话说自从昨天被维修数列那题榨干之后我现在写splay都不用动脑子了,,机械式的码spla ...

  4. 【XSY1522】灯 乱搞

    题目大意 ​ \(n\)盏灯排成一列,标号\(1\)到\(n\),一开始标号为\(1\)的灯亮着. ​ 现在依次对于\(2\)~\(n\)的每一个质数\(p_i\),指定一盏亮着的灯\(a_i\),点 ...

  5. bzoj 2733 : [HNOI2012]永无乡 (线段树合并)

    Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...

  6. SSL加速卡调研的原因及背景

    SSL加速卡调研的原因及背景 SSL加速卡调研的原因及背景 网络信息安全已经成为电子商务和网络信息业发展的一个瓶颈,安全套接层(SSL)协议能较好地解决安全处理问题,而SSL加速器有效地提高了网络安全 ...

  7. php+redis配置

    系统环境: win10+phpstudy+lamp 安装扩展 php5.6.4 =>下载地址:http://windows.php.net/downloads/pecl/releases/red ...

  8. 【 HDU 2177 】取(2堆)石子游戏 (威佐夫博弈)

    BUPT2017 wintertraining(15) #5C hdu2177 题意 两个人轮流取石子,可以取一堆的任意非负整数个或两堆取相同个,先取完的输. 给定若干组数据:a,b表示两堆的石子数量 ...

  9. LOJ#2019. 「AHOI / HNOI2017」影魔

    题意: 在一个序列中 如果有一个子区间 它有一个端点是区间最大值 另一个端点不是这个区间的次大值 就会有p2的贡献 它两个端点分别是最大值次大值 就会有p1的贡献 我们发现这两个条件有一个重合的部分 ...

  10. 【dfs】p1731 生日蛋糕

    1441:[例题2]生日蛋搞 [题目描述] 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体.设从下往上数第i(1≤i≤M)层蛋糕是半径为Ri, 高 ...