博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PoEdu - C++阶段班【Po学校】- Lesson03-4_构造函数&赋值函数&拷贝构造函数&学习方式 - 第6天...
阅读量:7112 次
发布时间:2019-06-28

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

 

PoEdu - C++阶段班【Po学校】- 第6天

 课堂选择题目:

1  关于转换构造函数  ClassDemo demo = 1;  调用转换构造函数

2  关于拷贝赋值函数  demo =2;

  首先创建一个临时对象,再调用operator=

3  自己手动加了一个函数在头文件:ClassDemo& operator=(const int other); 那么demo =2 ;调用了什么:

  这里此时不会调用构造函数,而是直接调用operator=

4  ClassDemo demo1 = demo;  这行是不是赋值?

  不是赋值,它相当于ClassDemo demo1(demo);是构造函数。偶有一个新的对象产生,100%就需要调用构造函数。

 5 demo =20;这句代码相当于: demo.operator=(ClassDemo(20));

 


--> 拷贝构造函数

1.0  拷贝构造函数,是默认生成的,你不写编译器会自动生成。注意它的参数,一定是一个引用。

1.1  来看下面示例:

 ClassDemo.h

#ifndef _ClASSDEMO_H_#define _CLASSDEMO_H_namespace PoEdu{    class ClassDemo    {    public:        ClassDemo();        ClassDemo(int num);            ClassDemo(const ClassDemo& other);        ~ClassDemo();        ClassDemo& operator=(const ClassDemo& other);                int GetNum();    private:        int _num;    };}#endif  //!_CLASSDEMO_H_

ClassDemo.cpp

#include "ClassDemo.h"#include 
namespace PoEdu{ ClassDemo::ClassDemo() { std::cout << "ClassDemo()" << std::endl; } ClassDemo::ClassDemo(int num ) { _num = num; std::cout << "转换构造ClassDemo(" << num << ")" << std::endl; } ClassDemo::ClassDemo(const ClassDemo & other) { std::cout << "拷贝构造ClassDemo(const ClassDemo& other)……被调用 " << _num << std::endl; _num = other._num; } ClassDemo::~ClassDemo() { std::cout << "析构函数~ClassDemo( " << _num << ")" << std::endl; } ClassDemo& ClassDemo::operator=(const ClassDemo& other) { std::cout << "operator=()……被调用 " <<_num << std::endl; _num = other._num; return *this; } int ClassDemo::GetNum() { return _num; }}

main.cpp

#include "ClassDemo.h"#include 
int main(){ using namespace PoEdu; ClassDemo demo (1); demo = 2; ClassDemo demo1 = demo; std::cout << demo.GetNum() << std::endl; return 0;}

F10运行:

1.2  看ClassDemo.cpp那边代码图

继续F10,拷贝赋值

 

继续F10,

看看调用的是哪里:

接着就是打印,最后析构 

 

1.4  拷贝构造函数的格式,要注意:参数里面一定是一个引用,如果不是引用,会发生什么结果:

1.5  编译器编译不成功,为什么会编译失败呢?这里面会有一个“无限递归”的问题出现。  答:如果手动写拷贝构造时,一定要注意参数,它一定是一个引用,如果不用引用,会产生一个严重的问题:无限递归

  函数的形参,会被实参化,怎么实参化呢,它会调用一个拷贝,那么,又回到了本身,我们要写的就是拷贝构造函数,这里无限递归就形成了。编译一定是通不过的。

 

1.6  再看示例:

1.7  方法1,产生一个临时对象,这个临时对象是拷贝构造直接生成的,使用了这个临时对象后,立即销毁了。

1.8  再看方法2 f2完全没有对象的产生。

1.9  方法2传递的是当前对象的一个引用。没有调用构造函数,产生对象。

1.10  注意:能用引用就要用引用,但纯引用会改变变量的值,很危险,那么,就要加const,所以引用要配合const使用。


 -->空类  生成默认函数

 

2.0  一个空类,编译器会自动生成哪几种默认函数:

2.1  构造

2.2  析构

2.3  拷贝构造

2.4  赋值

2.5  有了参数后,哪些会发生改变:1 构造  不改变,2 析构不改变  3 拷贝构造改变  4  拷贝赋值 改变

2.6  注意4 个自动生成的函数中,当手动写了一个构造,那么默认的构造函数就没了。


 

--> 浅拷贝 & 深拷贝

3.0  MyString类的示例:

#define _CRT_SECURE_NO_WARNINGS#include 
class MyString{public: MyString() { _len = 100; _str = new char[_len]; } MyString(char* str):_len(strlen(str)) { _str = new char[_len + sizeof(char)]; strcpy(_str, str); } ~MyString() { if (_str) delete[]_str; } char* GetString() { return _str; }private: char *_str; int _len; };int main(){ MyString str("I love Mark!!"); MyString sb = str; std::cout << sb.GetString() << std::endl; return 0;}

3.1  以上代码一点问题也没有,但如果我要加一句呢?请看:

#define _CRT_SECURE_NO_WARNINGS#include 
class MyString{public: MyString() { _len = 100; _str = new char[_len]; } MyString(char* str):_len(strlen(str)) { _str = new char[_len + sizeof(char)]; strcpy(_str, str); } ~MyString() { if (_str) delete[]_str; } char* GetString() { return _str; }private: char *_str; int _len; };int main(){ MyString str("I love Mark!!"); MyString sb = str; std::cout << sb.GetString() << std::endl; sb = "I Need Mark!!"; std::cout << sb.GetString() << std::endl; return 0;}

运行结果:

I love Mark!!

葺葺葺葺葺葺葺葺葺0

乱码出现。分析为什么乱码会出现 :

代码 sb = "I Need Mark!!";这里可以分解为3个步骤,1构造临时对象并传递参数(“I Need Mark!!”),参数是一个指针 

2调用拷贝赋值函数:operator(MyString&)(sb._str = temp._str; _len = temp._len);注意高亮部分sb._str = temp._str;这是指针的赋值,指针是内存地址。

 

 vs编译器在debug版本下,把野指针赋值为  0xdddddddd .在Vs2015编译器debug版本下面,未经初始化的值赋值为:0xCCCCCCCC,已经被delete的值赋值为:0xDDDDDDDD.

直接对指针赋值的拷贝,就是浅拷贝。浅拷贝没有维护参数的生命周期,给别人维护。

深拷贝就是考虑了数据的完整度的拷贝动作,对比浅拷贝,它维护了对象所有参数的生命周期,所有参数的生命周期和我的对象是同步的:

 


 学习方法,反复嘱咐:基础很重要,基础知识点,要做到了如指掌。

 

转载于:https://www.cnblogs.com/bing-z/p/6238333.html

你可能感兴趣的文章
内核通知链 学习笔记 【转】
查看>>
Input Method of Win32 System
查看>>
count(*) VS count(X)
查看>>
MS ASP.Net Ajax 服务端扩展
查看>>
android102 查询,插入联系人
查看>>
数据库邮件
查看>>
adstrtal.sh报超时错误 ERROR : Timed out( 100000 ): Interrupted Exception
查看>>
一个前端工程师的基本修养
查看>>
ZT:三十个好习惯
查看>>
.Net开发笔记(七)使用组件编程
查看>>
ASP.NET企业开发框架IsLine FrameWork系列之八--AppLogProvider日志框架(下)
查看>>
DataBase异常状态:Recovery Pending,Suspect,估计Recovery的剩余时间
查看>>
一个android版本的rss阅读器--明天补充实现过程,先上图
查看>>
WPF TreeView
查看>>
HTML: 仿写一个财经类静态的网页
查看>>
POJ 3979 分数减法【数学问题的探讨】
查看>>
HashSet
查看>>
C#读写config配置文件
查看>>
JavaScript:文本域事件处理
查看>>
关于dctser进程
查看>>