C++ Primer Plus----第十二章--类和动态内存分布

发布时间:2023年12月29日

本章内容包括:对类成员使用动态内存分配;隐式和显式复制构造函数;隐式和显式重载赋值运算符;在构造函数中使用new所必须完成的工作;使用静态类成员;将定位new运算符用于对象;使用指向对象的指针;实现队列抽象数据类型(ADT)。

12.1 动态内存和类

C++在分配内存时采取的策略是让程序在运行时决定内存分配,而不是在编译时再做决定。C++使用new和delete运算符来动态控制内存。遗憾的是,在类中使用这些运算符就会出现许多新的编程问题。在这种情况下,析构函数将是必不可少的。

  1. 让程序在运行时决定内存分配,而不是在编译时决定。
  2. C++使用new和delete运算符来动态控制内存,在类中使用这些运算符,析构函数将是必不可少的。
  3. 类对象定义的字符串并不保存在对象中。字符串单独保存在堆内存中,对象仅保存了指出到哪里去查找字符串的信息。
  4. 在构造函数中使用new来分配内存时,必须在相应的析构函数中使用delete来释放内存。如果使用new[](包括中括号)来分配内存,则应使用delete[](包括中括号)来释放内存。
12.1.1 复习示例和静态类成员

程序清单12.1,12.2,12.3;一个不完整的类,类方法实现,演示了StringBad类的构造函数和析构函数何时运行以及如何运行的; · d1e76f9 · Kite/C和C++ - Gitee.com

?上述代码需要注意的有两点,私有成员中使用了char指针,而不是char数组来表示姓名。这意味着类声明没有为字符串本身分配存储空间,而是在构造函数中使用new来为字符串分配空间。这避免了在类声明中预先定义字符串的长度。

其次,将num_strings成员声明为静态存储类。静态存储类有一个特点:无论创建了多少对象,程序都只创建一个静态类变量副本

?下面解释一下程序清单12.2,

int StringBad::num_strings = 0;// 初始化静态变量,用于记录创建的类数量

????????不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存。

????????对于静态类成员,可以在类声明之外使用单独的语句来进行初始化,这是因为静态类成员是单独存储的,而不是对象的组成部分。

????????注意,初始化部分指出了类型,并使用了作用域运算符,但是没有使用关键字static。

????????静态数据成员在类声明中声明,在包含类方法的文件中初始化。初始化时使用作用域运算符来指出静态成员所属的类。但如果静态成员是const整数类型或枚举型,则可以在类声明中初始化。

? ? ? ? 说明一下为什么不要在类声明中初始化,这是因为类声明位于头文件中,这个头文件可能在多个文件中引用,那么就会出现多个初始化语句副本,也就是重复了,就会引发错误。

StringBad::StringBad(const char * s)
{
    // str = s;             // 这只保存了地址,而没有创建字符串副本。
    len = std::strlen(s);   // 不包括末尾的空字符
    str = new char[len+1];  // 使用new分配足够的空间来保存字符串,然后将新内存的地址赋给str成员。
    std::strcpy(str, s);
    num_strings++;
    cout << num_strings << " : \"" << str << "\" object created.\n";
}

String boston(“Boston”);//可以这么用,字符串就是地址

?????????看一下这个非默认构造函数,首先strlen()计算字符串的长度,但不包括末尾的空字符,所以需要将len+1。

? ? ? ? strcpy()函数是将后者复制到前者。

? ? ? ? 这种方法,字符串并不保存在对象中,字符串单独保存在堆内存中。

? ? ? ? 最后析构函数,当对象过期时,str指针也将过期。但str指向的内存仍被分配,除非使用delete释放。删除对象可以释放对象本身占用的内存,但并不能自动释放属于对象成员的指针指向的内存。因此,必须要使用析构函数。在析构函数中使用delete语句可确保对象过期时,由构造函数使用new分配的内存被释放。

? ? ? ? 由于缺陷比较多,所以可能运行输出结果是不确定的。输出中出现的各种非标准字符随系统而异。

? ? ? ? ?程序执行到这里应该还是没有问题的(也许只是看起来);

 callme1(headline1);

? ? ? ? 当执行到这里就会出现明显的错误了,callme2()按值(而不是按引用)传递headline2。

callme2(headline2); // 复制构造函数被用来初始化 callme2()的形参

?

文章来源:https://blog.csdn.net/qq_45796666/article/details/135286320
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。