第十二章 类的和动态内存分配

这篇博客探讨了C++中动态内存管理在类中的应用,特别是构造函数和析构函数的角色。强调了使用new和delete管理内存的重要性,以及如何通过复制构造函数和赋值运算符实现深拷贝。还提到了静态成员函数的特点和使用注意事项,以及在构造函数中使用new的细节。此外,讨论了返回对象的效率问题,推荐使用const引用以避免不必要的复制构造函数调用。最后,简要介绍了队列模拟和成员初始化列表的语法。
摘要由CSDN通过智能技术生成

12.1 动态内存和类

构造函数使用常规C字符串来初始化String对象

StingBad::StringBad(const char * s)
{
	len = std::strlen(s);
	str = new char[len + 1];
	std::strcpy(str, s);
}
  • 使用strlen()函数计算字符串的长度,并对len成员进行初始化。
  • 使用new分配足够的空间来保存字符串,然后将新内存的地址赋给str成员【strlen()返回字符串的长度,但不包括末尾的空字符】
  • 使用strcpy()将传递的字符串赋值到新的内容中【字符串并不保存在对象中,字符串单独保存在堆内存中,对象仅保存了指出到哪里去查询字符串的信息】
  • 删除对象可以释放对象本省占用的内存,但并不能自动释放属于对象成员的指针指向的内存,因此,必须使用析构函数,在析构函数中使用delete语句可确保对象过期时,由构造函数使用new分配的内存被释放。

特殊的成员函数

  • 默认构造函数,如果没有定义构造函数
  • 默认析构函数,未定义
  • 复制构造函数,未定义
  • 赋值运算符,未定义
  • 地址运算符,未定义

默认构造函数

  • 带参数的构造函数也可以是默认的构造函数,只要所有的参数都有默认值
    Klunk(int n = 0) {klunk_ct = n; }

复制构造函数

  • 用于将一个对象复制到新创建的对象中
    Class name(const Calss_name &);
  • 何时调用?新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用,没当函数生成了对象副本时,编译器都会使用复制构造函数,具体地说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数,按值传递意味着创建原始变量的一个副本,编译器生成临时对象时,也将使用复制构造函数
    StringBad ditto(motto);
    StringBad metoo = motto;
  • 由于按值传递对象将调用复制构造函数,因此应该按引用传递对象,这样节省调用构造函数的时间以及存储新对象的空间

默认的复制构造函数功能

  • 默认的复制构造函数逐个复制非静态成员(成员赋值也被称为浅复制),复制的是成员的值
    StringBad sailor = sports;
    ==
    StringBad sailor;
    sailor.str = sports.str;
    sailor.len = sailor.len;

  • 如果成员本事就是类对象,则将使用这个类的复制构造函数来复制成员对象。静态成员不受影响,因为它们属于整个类,而不是各个对象

  • 使用复制构造函数来创建一个临时对象,然后通过赋值将临时对象的值赋值到新对象中,这就是说,初始化总是会调用赋值构造函数,而使用=运算符时也允许调用赋值运算符

C++11引入新关键字 nullptr

12.2 改进后的String类

静态类成员函数

可以将成员函数声明为静态的,这样做有两个重要的后果

  • 不能通过对象调用静态成员函数,如果静态成员函数是在公有部分声明的,则可以使用类名和作用域解析运算符来调用它
  • 其次,由于静态成员函数不与特定的对象相关联,因此只能使用静态数据成员

12.3 在构造函数中使用new时应注意的事项

  • 如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete
  • new和delete必须相互兼容,new对应delete,new[]对应delete[]
  • 如果有多个构造函数,则必须以相同的方式使用new,要么都带中括号,要么都不带
  • 应定义一个复制构造函数,通过深度复制将一个对象初始化为另一个对象
  • 应定义一个复制运算符,通过深度复制将一个对象复制给另一个对象
String& String::operator=(const String& str)
{
	ifthis == &str)
		return *this;
	delete[] str;
	len = st.len;
	str = new char [len + 1];
	std::strcpy(str, st.str);
	return *this
}

12.4 有关返回对象的说明
使用const引用的常见原因是旨在提高效率

const Vector & Max(const Vector & v1, const Vector & v2)
{
	if(v1.magval() > v2.magval())
		return v1;
	else
		return v2;
}
  • 首先,返沪对象将调用复制构造函数,而返回引用不会。因此,该版本工作更少,效率更高,其次,引用指向的对象应该在调用函数执行时存在。

12.7 队列模拟

成员初始化列表语法
Classy:Classy(int n, int m) :mem1(n), mem2(0), mem3(n*m + 2)

  • 这些初始化工作时在对象创建时完成,此时还未执行括号中的任何代码
  • 这种格式只能用于构造函数
  • 必须用这个格式来初始化非静态const数据成员
  • 必须用这个格式来初始化引用数据成员
    数据成员被初始化的顺序与它们出现在类声明中的顺序相同,与初始化器中的排列顺序无关,不能将成员初始化列表语法用于构造函数之外的其他类方法

C++11允许以更直观的方式进行初始化
class Classy
{
int mem1 = 10;
const int mem2 = 20;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值