《C++ Primer Plus》学习笔记7

《C++ Primer Plus》学习笔记7

第12章 类和动态内存分配

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

1、动态内穿和类

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

2)new分配足够的内存的时候一般都是这种形式

len = strlen(s);
str = new char[len + 1];

这样做的目的是使分配的内存能够存储包含空字符的字符串。

3)在构造函数中使用new来分配内存时候,必须在相应析构函数中使用delete来释放内存,如果使用new[]来分配内存,则应使用delete[]包含中括号来释放内存。

4)隐式成员函数

C++自动提供下面这些成员函数:

默认构造函数;

复制构造函数;

赋值操作符;

默认析构函数;

地址操作符;

5)改进后的新string类

①修订后的默认构造函数

 String::String()
    {
        len = 0;
        str = new char[1];//为什么不使用str = new char上面两种方式分配的内存量相同,区别在于前者和析构函数兼容,后者不兼容。析构函数中包含delete[] str;

        str[0] = ‘\0‘;
    }

②比较成员函数

要实现字符串比较的函数,最简单的方法是使用标准的strcmp()函数,如果按照字母顺序,第一个参数位于第二个参数之前,则该函数返回一个负值;如果两个字符串相同,则返回0;如果第一个参数位于第二个参数之后,则返回一个正值。

bool operator< (const String &st1, const String &st2)
{
    if(std::strcmp(st1.str, st2.str) > 0)
        return true;
    else
        return false;
}

因为内置的 > 操作符返回一个布尔值,所以可以继续简化为

bool operator< (const String &st1, const String &st2)
{
    return (std::strcmp(st1.str, st2.str) < 0);
}
bool operator> (const String &st1, const String &st2)
{
    return st2.str < st1.str;
}
bool operator== (const String &st1, const String &st2)
{
    return (std::strcmp(st1.str, st2.str) == 0);
}

6)如果编译器没有实现布尔类型的话,可以使用int代替bool,0代替false,1代替true。如果编译器不支持静态类常量,可以用枚举来定义CINLIM

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

①如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete

②new和delete必须相互兼容,new对应delete,new[]对应delete[]

③如果有多个构造函数,则必须以相同的方式使用new,要么带中括号,要不都不带,因为只有一个析构函数,因此所有的构造函数都必须与它兼容,不过,可以在一个构造函数中使用new来初始化指针,而在另一个构造函数中将指针初始化为空,这个是因为delete可以用于空指针。

8)有关返回对象的说明

①返回指向const对象的引用

使用const引用的常见原因是旨在提高效率。

//version1
Vector Max(const Vector & v1, const Vector & v2)
{
    if(v1.magval() > v2.magval())
        return v1;
    else
        return v2;
}
//version2
const Vector & Max(const Vector & v1, const Vector & v2)
{
    if(v1.magval() > v2.magval())
        return v1;
    else
        return v2;
}

注意:返回对象将调用复制构造函数,但是返回将不会。效率高

引用指向的对象应该再调用函数执行时存在;

v1和v2都被声明为const引用,因此返回类型必须是const,这样才能匹配

②使用指向对象的指针

String * favorite = new String(sayings[choice]);

这不是为要存储的字符串分配内存,而是为对象分配内存;也就是说,为保存字符串地址的str指针和len成员分配内存,程序员并没有给num_string成员分配内存,因为num_string成员是静态成员,它独立于对象被保存。

③下面几种情况析构函数将被调用

如果对象是动态变量,则当执行完定义该对象的程序块时候,将调用该对象的析构函数;

如果对象是静态变量(外部、静态、静态外部或来自名称空间),则在程序借结束时候将调用对象的析构函数

如果对象是用new创建的,则仅当显式使用delete删除对象时,析构函数才会被调用

9)指针和对象的小结

①使用常规法来声明指向对象的指针

String * glamour;

②可以将指针初始化为指向已有的对象

String * first = &sayings[0];

③可以使用new来初始化指针,这将创建一个新的对象

String * favorite = new String(saying[choice])

④对类使用new将调用相应的类构造函数来初始化新的创建对象

String * gleep = new String;
String * glop = new String("my my my");
String * favorite = new String(sayings[choice]);

⑤可以使用->操作符通过指针访问类方法

if(sayings[i].length() < shortest -> length())

⑥可以对对象指针应用解除引用操作符()来获得对象

if(sayings[i] < first)

first = &sayings[i];

10)布局new操作符

能够让您在分配内存时指定内存位置

在布局new操作符来为对象分配内存,必须确保其析构函数被调用。

对于堆中创建的对象,可以使用

delete pc2;

对于使用布局new操作符创建的对象,不能像下面这么做

delete pc1;

原因在于delete可与常规new操作符配合使用,但不能与布局new操作符配合使用。

解决方法显式地为使用布局new操作符创建的对象调用析构函数,采用pc1 ->~JustTesting();

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

总结:处理各种与类相关问题的编程技术

1)重载<<操作符

要重新定义<<操作符,以便将它与cout一起用来显示对象的内容,定义下面友元操作符函数:

ostream & operator<< (ostream & os, const c_name & obj)
{
    os << ……; //display object contents
    return os;
}

2)转换函数

要将单个值转换为类类型,需要创建原型如下所示的类构造函数

c_name(type_name value) 其中c_name为类名 type_name是要转换的类型的名称

要将类转换为其他类型,需要创建原型如下所示的类成员函数

operator type_name();虽然该函数没有声明返回类型,但应返回所需要类型的值

使用转换函数要小心,可以在声明构造函数时候使用关键字explicit,以防止被用于隐式转换。

2、队列模拟

队列是一个抽象的数据类型(ADT),可以存储有序的项目序列,新项目被添加在队尾,并且可以删除队首的项目。队列与堆栈不一样的是堆栈在同一端进行添加和删除,这使得栈是一个后进先出的结构,而队列是先进先出的。

1)Queue类的实现

因为队列操作每删除第一个元素后,需要将余下的所有元素向前移动一位;故不适合用数组来完成。所有我们这里采用链表,链表是由节点序列构成,每个节点中都包含要保存到链表信息以及一个指向下一节点的指针。对于队列来说,数据部分多事一个Item类型的值,使用下面结构来表示节点

struct Node
{
    Item item;
    struct Node * next;
}

2)嵌套结构和类

在类声明中声明的机构、类或枚举被称为是被嵌套在类中,其作用域为整个类,这种声明不会创建数据对象,而只是指定了可以在类中使用的类型

C++允许在类中包含结构、类、枚举定义作用域为整个类,这就意味着他们被局限于类中,并不会与别的发生冲突。

3)小技巧,怎么表示一个随机过程平均每6分钟来一个客户

bool newcustomer(double x)
{
    return (std::rand() * x/RAND_MAX < 1);//RAND_MAX实在cstdlib中定义的,是rand()可能返回的最大值,所以rand() * x/RAND_MAX的值将在0-6之间
}

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

小结:

如果对象包含指向new分配的内存的指针成员,则将一个对象初始化为另一个对象,或将一个对象赋给另一个对象,也会出现问题,在默认情况下,C++做个对成员进行初始化和赋值,这就意味着被初始化或被赋值的对象的成员与原始对象完全相同,如果原始对象的成员指向一个数据块,则副本成员将指向同一个数据块。解决方法是定义一个特殊的复制构造函数来重新定义初始化,并重载赋值操作符,新的定义将创建指向数据的副本,并使新对象指向这些副本,这样,旧对象和新对象都将应用独立的相同的数据,不会重叠。对于每种情况,最终母的是执行深度复制,也就是说复制数据,而不仅仅是复制指向数据的指针。

《C++ Primer Plus》学习笔记7,布布扣,bubuko.com

时间: 2024-08-09 21:49:22

《C++ Primer Plus》学习笔记7的相关文章

vector 学习笔记

vector 使用练习: /**************************************** * File Name: vector.cpp * Author: sky0917 * Created Time: 2014年04月27日 11:07:33 ****************************************/ #include <iostream> #include <vector> using namespace std; int main

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细,自己在看它的文档和代码时写了一些demo和笔记,还有它实现的原理记录一下 学习Caliburn.Micro要有MEF和MVVM的基础 先说一下他的命名规则和引导类 以后我会把Caliburn.Micro的 Actions IResult,IHandle ICondu

jQuery学习笔记(一):入门

jQuery学习笔记(一):入门 一.JQuery是什么 JQuery是什么?始终是萦绕在我心中的一个问题: 借鉴网上同学们的总结,可以从以下几个方面观察. 不使用JQuery时获取DOM文本的操作如下: 1 document.getElementById('info').value = 'Hello World!'; 使用JQuery时获取DOM文本操作如下: 1 $('#info').val('Hello World!'); 嗯,可以看出,使用JQuery的优势之一是可以使代码更加简练,使开

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

Activiti 学习笔记记录(三)

上一篇:Activiti 学习笔记记录(二) 导读:上一篇学习了bpmn 画图的常用图形标记.那如何用它们组成一个可用文件呢? 我们知道 bpmn 其实是一个xml 文件

HTML&CSS基础学习笔记8-预格式文本

<pre>标签的主要作用是预格式化文本.被包围在 pre 标签中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. <pre>标签的一个常见应用就是用来表示计算机的源代码.当然你也可以在你需要在网页中预显示格式时使用它. 会使你的文本换行的标签(例如<h>.<p>)绝不能包含在 <pre> 所定义的块里.尽管有些浏览器会把段落结束标签解释为简单地换行,但是这种行为在所有浏览器上并不都是一样的. 更多学习内容,就在码芽网http://www.

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

[原创]java WEB学习笔记48:其他的Servlet 监听器:域对象中属性的变更的事件监听器 (3 个),感知 Session 绑定的事件监听器(2个)

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过

[原创]java WEB学习笔记12:一个简单的serlet连接数据库实验

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------