Linux/C++系统编程 day6

类与对象

拷贝构造函数

  • 类名 (const 类名 &rhs)

  • 默认情况下编译器会自动生成拷贝构造函数

    (浅拷贝,如果有用到new需要手写一个深拷贝)

//常见调用形式
Point pt1(1, 2);
Point pt2 = pt1;

调用时机

  • 用一个已经存在的对象初始化另一个新对象

  • 函数的形参和传入的实参都是对象,进行实参与形参的结合时

  • 当函数的返回值是对象,函数调用完成返回时

    (编译器优化选项 -fno-elide-constructors 关闭优化

    C++标准允许一种(编译器)实现省略创建一个只是为了初始化另一个同类型对象的临时对象,实际上调用了拷贝构造函数之后析构)

注意const和&

  • 使用&原因:不可以去掉&,值传递要创建对象,创建对象要初始化调用拷贝构造函数,如此循环使用拷贝构造函数直到栈溢出,防止拷贝构造函数进入死循环。

  • 使用const原因:不可以去掉const,非const左值引用不能绑定到右值。当传递右值的时候,在执行拷贝构造函数的时候无法匹配右值。

浅拷贝

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BYBpF8QM-1610350977914)(\image-20210107111712142.png)]

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6xkI2ov3-1610350977916)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210110155959158.png)]

  • 两者指向同一个堆空间的字符串,这种只拷贝指针地址的方式,我们称为浅拷贝。当其中一个对象被销毁时,另外一个对象就获取不到相应的_brand 值了。

深拷贝

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3faugu3H-1610350977916)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210107111825007.png)]

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cD6esVvS-1610350977918)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210110160011658.png)]

  • 因为两个对象都拥有各自的独立堆空间字符串,一个对象销毁时就不会影响另一个对象。

lvalue与rvalue

  • 左值是对应内存中有确定存储地址的对象的表达式的值,其余为右值

  • 字面值常量(1234567890)、匿名对象、临时对象都属于右值的一种形式,比如函数

  • 左值可以放到赋值符号左边,非const的左值不能=(绑定)到右值

  • 右值可能存在寄存器上或者栈上超短时间就消失

  • 左值:可以取地址

  • 右值:不可取地址

隐含this指针

  • *const this指向对象本身,隐藏于(非静态)成员函数第一个参数的位置

  • 可以修改指针内容,不能修改指向

  • 类的所有对象共用这个成员函数体。 当程序被编译之后,此成员函数地址即已确定。而成员函数之所以能把属于此类的各个对象的数据区别开, 就是靠这个this指针。函数体内所有对类数据成员的访问, 都会被转化为this->数据成员的方式。

  • .左边是实体,提取右边成员

  • ->左边是指针,也可以提取指向的实体的成员

赋值运算符函数

  • 类通过调用成员函数操作数据成员
  • 在类外定义时作用域限定符加在&右边
//常见调用形式
pt2.operator=(pt1);
pt2 = pt1;//浅拷贝

默认浅拷贝

  • 只拷贝指针地址
  • 赋值运算符函数
//默认情况下,编译器会自动生成赋值运算符函数
Point &operator=(const Point &rhs){
	_ix=rhs._ix;
	_iy=rhs._iy;
	return *this;
}
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HeMNLObu-1610350977918)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210107155832331.png)]

正确深拷贝

  • 拷贝指针所指内容

  • 构造函数调用之后就有一块空间,正确做法

    • 先delete再nullptr

    • 之后申请新的空间让其指向新空间,把内容拷过来,使用深拷贝

      (直接拷过来可能会内存不够)

  • 赋值运算符函数

Compter & operator=(const Computer &rhs){
   //防止不能自赋值
   if(this != &rhs){//不能使用*this!= rhs尚未定义运算!=表示所指内容不等
   //释放原始堆空间
	delete [] _brand;
	_brand = nullptr;
   //深拷贝
	_brand = new char[strlen(rhs._brand)+1]();
	strcpy(_brand,rhs._brand);
	_price = rhs._price;//常量浅拷贝没关系
   }
	return *this;//返回this解引用内容
}

注意返回类和&

  • 赋值运算符返回&符号:不可以去掉,会在return语句中重复执行拷贝构造函数

  • 赋值运算符函数返回类型是类:不可以修改,连续赋值时会报错

  • 参数列表中的const和&思考方式同拷贝构造函数

特殊数据成员

常量const数据成员

  • 初始化必须在初始化列表中,不能在构造函数等任何成员函数内赋值

引用&数据成员

  • 初始化必须在初始化列表中

  • 引用占用一个指针大小的空间

  • 只有数据成员算占类的大小,其余编译成二进制文件存放在程序代码区(只读段),sizeof(类名),64位机器占8B

  • sizeof(对象) > 0 是因为标准规定完整对象的大小为正数,若为0,则不能区分该类实例化出的实例,为了实现每个实例在内存中都有一个独一无二的地址,编译器往往会给一个空类隐含的加一个字节

类对象成员

  • 初始化必须在初始化列表中,对所有的参数初始化

    (比如一个直线类Line 对象中包含两个Point 类对象,对
    Point对象的创建就必须要放在Line 的构造函数的初始化列表中进行)

静态static数据成员

  • 静态数据成员初始化必须在类的外面,不能在初始化列表中初始化

  • 如果放在头文件中会有在执行文件和类定义文件中多重定义,应放在实现文件中

    (#ifndef 只能防止在一个文件中重定义)

  • 静态数据成员不受pubic、private修饰符限制

    (在全局静态区中,不占用类的大小,float因为内存对齐与指针一起成为成员函数时会变成8B)

特殊成员函数

静态static成员函数

  • 静态成员函数在类外static应省略简写,不然会报错

  • 静态成员函数的参数列表中不含有隐含的this指针,被所有对象共享

  • 静态成员函数内部只能调用静态数据成员和静态的成员函数

    (如果要调用非静态数据成员可以在参数列表使用&传参)

  • 直接通过类名和作用域限定符也可以调用静态成员函数,普通成员函数不能这样调用(未实例化)

常量const成员函数

  • 放在函数小括号后面、花括号前面修饰

  • 两个同名的成员函数其中一个为const就可以重载

    (因为其中一个参数列表隐含*const this,

    而const成员函数隐含const *const this)

  • 只能读取类的数据成员不能修改

    (只读操作建议先定义const版本的)

  • 只能调用const成员函数不能调用非const成员函数
    放在函数小括号后面、花括号前面修饰

  • 两个同名的成员函数其中一个为const就可以重载

    (因为其中一个参数列表隐含*const this,

    而const成员函数隐含const *const this)

  • 只能读取类的数据成员不能修改

    (只读操作建议先定义const版本的)

  • 只能调用const成员函数不能调用非const成员函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值