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++知识库 -> 《Effective C++》条款31:将文件间的编译依存关系降至最低 -> 正文阅读

[C++知识库]《Effective C++》条款31:将文件间的编译依存关系降至最低

在学习了一段时间的C++后,开始读《Effective C++》。由于缺乏项目经验,平时写的程序大都也是在LeetCode和牛客上的C with STL,对编译过程也不太了解,所以读这一章时感觉有很多不理解的地方。在查阅了网上其他大佬对这一章的理解后,我想谈谈自己对这一条款的理解。

#include <string>
#include "date.h"
#include "address.h"

class Person {
 public:
     Person(const std::string& name, const Date& birthday, const Address& addr);
     std::string name() const;
     std::string birthDate() const;
     std::string address() const;
     //...
 private:
     /*成员变量*/
     std::string m_Name;
     Date m_BirthDate;
     Address m_Address;
 };

首先是开头的这一段程序,在Person类中,有三个成员变量,它们的类型是string、Date和Address。由于Person类的三个成员变量既不是指针也不是引用,所以编译器在编译这个文件时必须访问这三个类型的定义式,否则无法得知该给这三个变量分配多少内存。也就是说,如果你修改了Date或Address的定义,然后重新编译,Person类所在的文件也不得不重新编译。

现在,假如Person类的三个成员变量不是Object,而是指针或引用,那么你可以不用include date.h和address.h,而用两个声明代替它们(class Date;,class Address;)。此时,你再修改Date和Address的定义,然后重新编译,Person类所在的文件就不用重新编译。

#include <string>

class Date;
class Address;

class Person {
 public:
     Person(const std::string& name, const Date& birthday, const Address& addr);
     std::string name() const;
     std::string birthDate() const;
     std::string address() const;
     //...
 private:
     /*成员变量*/
     std::string* m_Name;
     Date* m_BirthDate;
     Address* m_Address;
 };

为什么这样就不用重新编译Person所在的文件呢?

首先,对于指针类型,它的大小是固定的,在64位的系统上是8字节,32位系统上是4字节,编译器不需要访问定义式就可以知道所需要的内存大小。由此可见,对于编译器来说,Person类的每一个成员变量类型和分配给成员变量的内存是明确的。

其次,编译器在编译的时候,是将每个文件单独编译,最后再将所有文件连接。因此,就算你修改了Date和Address的定义式,也不会影响到Person,因为编译person的时候不需要访问Date和Address。

如果是引用原理也是一样,因为引用的本质还是指针。

基于此,作者提出了两条建议:尽量用指针和引用代替Object;尽量用class声明代替class定义式。

为什么要用指针和引用代替object,上面已经说明。而为什么用class声明代替class定义,是因为在函数声明中,即使用到某个class,并不需要访问定义式,即使是使用by value的方式传参。(我个人看来,使用class定义式并不方便修改,因为一旦修改了定义式,整个文件都需要重新编译,哪怕你只是做了一个小小的修改)

#include <string>
#include <memory>
 
class PersonImpl;
class Date;
class Address;
class Person  {
public:
    Person( const std::string& name,const Date& birthday,const Address& addr);
    std::string name() const;
    std::string birthDate() const;
    std::address() const;
    ...
private:
   std::tr1::shared_ptr<PersonImpl> pImpl;
};

上述代码就应用了作者的两个建议。用class声明代替了class定义式,用指针代替了Object。使用这种方式的好处是降低了耦合。因为将类型的实现细节都放在了 PersonImpl中,如果你修改了PersonImpl的定义式,可以不用重新编译Person。

想象一下,假如你有数百个文件使用了Person类型的对象,如果你将所有细节都放在Person中,一旦你修改了Person类,这就意味着这数百个文件都要重新编译。万幸的是,你将Peson类的细节都放在了PersonImpl中,而Person类只使用了指针,就算你修改了PersonImpl,也只需要重新编译PersonImpl所在的文件就可以了。

像上文中的Person类被称为Handle class,而定义Handle class的方法还有另一种。具体细节就不表了,书本上都有,再写下去就变成抄书了。

如有错误请指出,万分感谢。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 11:33:43  更:2021-09-09 11:34:47 
 
开发: 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年11日历 -2024/11/23 19:41:38-

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