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--> 拷贝构造函数

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 <iostream> 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 <iostream> int main()
{
using namespace PoEdu; ClassDemo demo ();
demo = ; ClassDemo demo1 = demo; std::cout << demo.GetNum() << std::endl; return ;
}

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-->空类  生成默认函数

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

2.1  构造

2.2  析构

2.3  拷贝构造

2.4  赋值

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

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


3--> 浅拷贝 & 深拷贝

3.0  MyString类的示例:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream> class MyString
{
public:
MyString()
{
_len = ;
_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 ;
}

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

#define _CRT_SECURE_NO_WARNINGS
#include <iostream> class MyString
{
public:
MyString()
{
_len = ;
_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 ;
}

运行结果:

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.

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

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


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

PoEdu - C++阶段班【Po学校】- Lesson03-4_构造函数&赋值函数&拷贝构造函数&学习方式 - 第6天的更多相关文章

  1. PoEdu - C++阶段班【Po学校】- Lesson02_类与对象_第4天

    复习:上节作业讲解 注意点: 设计SetString()的时候,要注意重置原来的空间. char * SetString(const char *str) { _len = strlen(str); ...

  2. PoEdu - C++阶段班【Po学校】- 第3天

    引用 C中指针的功能强大,使用起来繁杂,因为指针要控制的东西太多:有指针的类型,指针的解引用,指针空间内的值,它本身是有空间的,有自己的地址等.指针也是强大的,比如:我们要在函数之内,修改方法之外的值 ...

  3. PoEdu - C++阶段班【Po学校】- 第1课

    1 C++开讲 C ++  伟大的编程语言:能提高程序运行效率,节约更多的资源,"正确的使用C++,能够抑制全球变暖问题". 2 C++能力雷达图 通过 1效率 2灵活度 3 抽象 ...

  4. PoEdu - C++阶段班- Lesson07 To Lesson10_C to C++

    07  重载导致的二义性 问题:为什么一定要重载呢?重载能方便我们注重函数的功能,当参数类型不确定时,我们能很便捷的利用重载的机制达到目的. 重载注意点:二义性 看代码: #include <c ...

  5. PoEdu - C++阶段班- Lesson02_C to C++

    1  原生bool类型 c++里面的bool类型才是真正原生的true和faul,比如常见的大写的"BOOL",它就不是原生的. 原生的与非原生的bool,它们的区别: 详细说下原 ...

  6. PoEdu- C++阶段班【Po学校】-Lesson03_构造函数精讲 - 第5天

    复习构造函数:1  与类同名   2  没有返回值   3  自动生成    4  手动后,不会自动生成    5  不在特定的情况下,不会私有  新建 类   两种方法示范   其一:在vs中选择类 ...

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

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

  8. 潭州课堂25班:Ph201805201 第八课:函数基础和函数参数 (课堂笔记)

    1, 函数定义 def fun(): print('测试函数') fun() #调用函数 return 运行函数返回值 def fun(): name = [1,3,4,5] return name[ ...

  9. C++的那些事:类的拷贝控制

    1,什么是类的拷贝控制 当我们定义一个类的时候,为了让我们定义的类类型像内置类型(char,int,double等)一样好用,我们通常需要考下面几件事: Q1:用这个类的对象去初始化另一个同类型的对象 ...

随机推荐

  1. zt:Linux查看程序端口占用情况

    http://www.cnblogs.com/benio/archive/2010/09/15/1826728.html yxr注: 由于安装eda工具libero,license要配端口,为确认端口 ...

  2. memcached tomcat maven 学习记录

    2016.12.11 maven 快速搭建项目,只要有pom.xml文件配置好依赖 可以把项目切割(具体切割出来的块怎么用?) nginx 负载均衡  文件服务器 主要配置nginx.conf 文件 ...

  3. c#判断闰年

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. List 泛型 集合中 Find 的用法

    以前在开发中为了对List,String[].Array进行元素的查找一般都是这样做:List lists = new List();list.add("111");.....fo ...

  5. 用EasyWebSvr搭建Axure本地访问地址-转载加完善

    1.下载之后解压到任意一个位置,可以是桌面(反正很小不占空间),如图2:: 图2 解压之后文件目录 2.将生成的原型放在EasyWebSvr根目录下的demo之中,如图3所示: 图3  原型文件放置目 ...

  6. Delphi 完整的Bug决议工具EurekaLog的使用

     http://blog.csdn.net/akof1314/article/details/6968587 Delphi 完整的Bug决议工具EurekaLog的使用 标签: delphi工具ftp ...

  7. hive中分号问题

    分号是sql的结束符,在hql中亦如此,但是hive对分号的识别没有那么智能,如下: select concat(';','aa') from lhc limit 1; FAILED: Parse E ...

  8. ORACLE临时表空间

    ORACLE临时表空间总结 2014-10-05 11:35 by 潇湘隐者, 临时表空间概念 临 时表空间用来管理数据库排序操作以及用于存储临时表.中间排序结果等临时对象,当ORACLE里需要用到S ...

  9. win7 双屏双任务栏

    扩展屏幕下都显示任务栏!!! 第一步:Dual Monitor Taskbar 下载 下载链接:链接: http://pan.baidu.com/s/1pKxYUFL 密码: gu5c 第二步:安装完 ...

  10. 史航416第八次作业&总结

    一.知识点总结: 1.数组的输入,输出及对整个数组所有元素进行操作通常都用循环结构实现. 2.可以只给部分元素赋初值.当{ }中值的个数少于元素个数时,只给前面部分元素赋值. 3.只能给元素逐个赋值, ...