IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 侯捷系列:c++面向对象高级编程(上) -> 正文阅读

[C++知识库]侯捷系列:c++面向对象高级编程(上)

基于对象的程序设计

不带有指针成员变量的类(以复数类Complex为例)

头文件的结构

头文件complex.h的结构如下,主要有4部分:
在这里插入图片描述

  • 防卫式声明:防止头文件被重复包含
  • 前置声明: 声明头文件中用到的类和函数
  • 类声明: 声明类的函数和变量,部分简单的函数可以在这一部分加以实现
  • 类定义: 实现前面声明的函数

访问级别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
类的声明内可以交叉定义多个不同级别的访问控制块:

class complex 
{
public:
	// public访问控制块1...
    
private:
    // private访问控制块1...

public:
    // public访问控制块2...

}

函数设计

内联函数

  • 在类声明内定义的函数,自动成为inline函数;
  • 在类声明外定义的函数,需要加上inline关键字才能成为inline函数.

inline只是编程者给编译器的一个建议,在编译时未必会真正被编译为inline函数.因此如果函数足够简单,我们就把它声明为inline就好了

构造函数

与其他语言类似,C++的构造函数也可以有默认实参.C++构造函数的特殊之处在于列表初始化(initialization list).

在这里插入图片描述
上面两种构造函数的效果是一样的,但是使用列表初始化的效率更高,应尽量使用列表初始化.

常量成员函数

若成员函数中不改变成员变量,应加以 const 修饰
在这里插入图片描述

参数的值传递和引用传递

在这里插入图片描述
为了提高效率,使用引用传递参数,避免了参数的复制.若不希望在函数体内对输入参数进行修改,应使用const修饰输入参数
函数的参数应尽量使用引用传递.

返回值的值传递和引用传递

在这里插入图片描述
为提高效率,若函数的返回值是原本就存在的对象,则应以引用形式返回.

若函数的返回值是临时变量,则只能通过值传递返回.

友元

友元函数不受访问级别的控制,可以自由访问对象的所有成员.
在这里插入图片描述
同一类的各个对象互为友元,因此在类定义内可以访问其他对象的私有变量
在这里插入图片描述

complex c1, c2;
c2.func(c1);		// 因为c1和c2互为友元,因此c2可以在func()函数内调用c1的私有变量

操作符重载

在C++中的操作符重载有两种形式:

  • 一种是在类内声明public函数实现操作函重载(这种情况下,操作符是作用在左操作数上的);
  • 另一种是在类外声明全局函数实现操作符重载.

为便于调用该类的用户使用,不同的操作符使用不同的方式进行重载。

在类内声明 public 函数重载 +=

输出参数类型为 complex& ,这是为了支持将多个 += 操作符串联起来.若返回参数类型设为 void ,也支持形如 c2+=c1 的运算,但不支持形如 c3+=c2+=c1 的运算.
在这里插入图片描述
函数体内调用友元函数 __doapl(complex *, const complex &) 实现功能,其第一个参数接收成员函数内隐含的 this 指针,其内容在函数中会被改变;第二个参数接收重载函数的参数,该参数在函数中不会被改变,以 const 修饰.
在这里插入图片描述

在类外声明或函数重载+

考虑到+操作符有三种可能的用法如下:

complex c1(2,1);
complex c2;

c2 = c1 + c2;	// 用法1: complex + complex
c2 = c1 + 5;	// 用法2: complex + double
c2 = 7 + c1;	// 用法3: double + complex

因为重载操作符的成员函数是作用在左操作数上的,若使用类内声明public函数重载操作符的方法,就不能支持第3种用法了.因此使用在类外声明函数重载+运算符.

在这里插入图片描述
这3个函数返回的是局部对象(local object),在退出函数时对象就会被销毁,因此不能使用引用传递返回值.

在类外声明函数重载<<

与重载 + 的考虑方法类似, << 操作符通常的使用方式是 cout<<c1 而非 c1<<cout ,因此不能使用成员函数重载 << 运算符.

虑到形如 cout<<c1<<c2<<c3 的级联用法,重载函数的返回值为 ostream& 而非 void.

在这里插入图片描述

总结:在编写类的时候应该注意的5件事

在编写类的时候应该注意的5件事,通过这5件事可以看出你写的代码是否大气:

  1. 构造函数中使用列表初始化(initialization list)为成员变量赋值.

  2. 常量成员函数使用const修饰.

  3. 参数的传递尽量考虑使用引用传递,若函数体内不改变传入的参数,应加以const修饰.

  4. 返回值若非局部变量,其传递尽量考虑使用引用传递,

  5. 数据放入private中,大部分函数放入public中.

带有指针成员变量的类——以字符串类String为例

在这里插入图片描述
类声明如下,使用指针成员变量m_data管理String类中的字符串数据.
在这里插入图片描述

3个特殊函数:拷贝构造函数、拷贝赋值函数和析构函数

对于不带有指针的类,这3个函数可以使用编译器默认为我们生成的版本;但是编写带有指针的类时就有必要定义这3个特殊函数.

构造函数和析构函数

构造函数和析构函数中执行数据的深拷贝和释放.
在这里插入图片描述

值得注意的是使用delete[]操作符释放数组内存,若直接使用delete操作符释放数组内存虽然能够通过编译,但有可能产生内存泄漏.

拷贝构造函数和拷贝赋值函数

注意拷贝3调用的是拷贝构造函数。

String s1 = "hello";
String s2(s1);      // 拷贝1: 调用拷贝构造函数
String s3;
s3 = s1;            // 拷贝2: 调用拷贝赋值函数
String s4 = s1;     // 拷贝3: 调用拷贝构造函数

拷贝构造函数的实现较为简单,直接调用友元对象的数据指针进行拷贝即可.

在这里插入图片描述
拷贝赋值函数中要检测自我赋值,这不仅是为了效率考虑,也是为了防止出现bug.

在这里插入图片描述
若在拷贝赋值函数中不检测自我赋值,在第2步中会出现bug.

堆栈与内存管理

https://blog.csdn.net/jialong_chen/article/details/115421050

new和delete过程中的内存分配

  • new操作先分配内存,再调用构造函数.
    在这里插入图片描述
  • delete操作先调用析构函数,再释放内存.

在这里插入图片描述
VC中对象在debug模式和release模式下的内存分布如下图所示,变量在内存中所占字节数必须被补齐为16的倍数,红色代表cookie保存内存块的大小,其最低位的1和0分别表示内存是否被回收.

Complex对象String对象
在这里插入图片描述在这里插入图片描述

数组中的元素是连续的,数组头部4个字节记录了数组长度:

Complex对象String对象
在这里插入图片描述在这里插入图片描述

根据数组在内存中的状态,自然可以理解为什么 new[] 和 delete[] 应该配对使用了: delete 操作符仅会调用一次析构函数,而 delete[] 操作符依次对每个元素调用析构函数.对于 String 这样带有指针的类,若将 delete[] 误用为 delete 会引起内存泄漏.
在这里插入图片描述

static成员

https://zhuanlan.zhihu.com/p/37439983

静态成员变量:类的所有对象共有。
静态成员函数:只能访问静态成员变量和静态成员函数。

面向对象(Object Oriented)的程序设计——类之间的关系

类之间的关系有复合(composition)、委托(aggregation)和继承(extension)3种.

类之间的关系

复合(composition)

复合表示一种has-a的关系,STL中queue的实现就使用了复合关系.这种结构也被称为adapter模式.
在这里插入图片描述
复合关系下构造由内而外,析构由外而内:
在这里插入图片描述

委托(aggregation;composition by reference)

在这里插入图片描述
使用类指针。

继承(extension)

继承表示一种is-a的关系,STL中_List_node的实现就使用了继承关系.
在这里插入图片描述
继承关系下构造由内而外,析构由外而内:
在这里插入图片描述

虚函数

成员函数有3种: 非虚函数、虚函数和纯虚函数

  • 非虚函數(non-virtual function): 不希望子类重新定义(override)的函数.

  • 虚函數(virtual function): 子类可以重新定义(override)的函数,且有默认定义.

  • 纯虚函數(pure virtual function): 子类必须重新定义(override)的函数,没有默认定义.
    在这里插入图片描述
    使用虚函数实现框架: 框架的作者想要实现一般的文件处理类,由框架的使用者定义具体的文件处理过程,则可以用虚函数来实现.

面向对象设计范例

使用委托+继承实现Observer模式

在这里插入图片描述
在这里插入图片描述

使用委托+继承实现Composite模式

使用Composite模式实现多态,类结构图如下
在这里插入图片描述

使用委托+继承实现Prototype模式

在这里插入图片描述

参考

https://blog.csdn.net/ncepu_Chen/article/details/113843775

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 11:53:50  更:2021-07-26 11:55:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/24 19:13:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码