zoukankan      html  css  js  c++  java
  • 读书笔记_Effective_C++_条款三十一:将文件间的编译依存关系降至最低(第二部分) 重新学习了 继续 三部分更加精彩

    假设我们要写一个Person类,如下:

    class Person
    {
    private:
        string name;
        MyDate birthday;
        MyAddress address;
    
    public:
        // fallows functions
        // ...
    };
    

      这个Person类里面包含有人的名字,人的生日以及地址,还有一些没有列出来的方法。注意到这里用到了string(它不是一个class,只是一个typedef,大多数情况下,我们认为它不会有任何改变),以及自定义的类MyDate与MyAddress,一种常见的做法是采用include头文件,像这样:

    1 #include <string>
    2 #include "MyDate.h"
    3 #include "MyAddress.h"
    

      在MyDate.h里面写好日期类相关的成员变量与方法,而在MyAddress.h里面写好地址类相关的成员变量与方法。

    但如果此后要往MyDate类或者MyAddresss类添加成员变量,那么不仅仅所有用到MyDate或者MyAddress对象的文件需要重新编译,而且所有用到Person对象的文件也需要重编译,一个小改动竟然会牵涉到这么多的地方!

    如果要把编译的依赖性降低,就要换一种思路来处理,不能出现定义式,只能出现声明式,代价是增加代码的复杂度以及性能上的一些损失。

    书上提到了两种方法,第一种是采用Handler Classes(用指针指向真正实现的方法)第二种是Interface Classes(抽象基类)。

    对于第一种Handler Class,一句话,就是.h里面不包含类的自定义头文件,用“class 类名”的声明方式进行代替(也要把相应的成员变量替换成指针或引用的形式),在.cpp文件里面包含类的自定义头文件去实现具体的方法。改造之后的程序看起来是这样子的:

    // Person.h
    #include <string>
    using namespace std;
    
    class PersonImp;
    
    class Person
    {
    private:
        //string Name;
        //MyDate Birthday;
        //MyAddress Address;
        PersonImp* MemberImp;//只有指针了 无对象了  该类型是抽出来的一个  方便管理后添加修改等操作 减低依赖关系的一种方法
    
    public:
        string GetName() const;
        string GetBirthday() const;
        string GetAddress() const;
        // follows functions
        // ...
    };
    // Person.cpp
    #include "PersonImp.h"
    #include "Person.h"
    
    string Person::GetName() const
    {
        return MemberImp->GetName();
    }
    string Person::GetBirthday() const
    {
        return MemberImp->GetName();
    }
    string Person::GetAddress() const
    {
        return MemberImp->GetAddress();
    }
    

      

    // PersonImp.h
    #ifndef PersonImp_H
    #define PersonImp_H
    
    #include <string>
    #include "MyAddress.h"
    #include "MyDate.h"
    using namespace std;
    
    class PersonImp
    {
    private:
        string Name;
        MyAddress Address;
        MyDate Birthday;
    
    public:
        string GetName() const
        {
            return Name;
        }
    
        string GetAddress() const
        {
            return Address.ToString();
        }
    
        string GetBirthday() const
        {
            return Birthday.ToString();
        }
    };
    
    #endif /* PersonImp_H */
    

      

    // MyDate.h
    #ifndef MY_DATE_H
    #define MY_DATE_H
    
    #include <string>
    using namespace std;
    
    class MyDate
    {
    private:
        int Year;
        int Month;
        int DayOfMonth;
    
    public:
        string ToString() const;
    }
    #endif /* MY_DATE_H */
    

      

    // MyAddress.h
    #ifndef MY_ADDRESS_H
    #define MY_ADDRESS_H
    
    #include <string>
    using namespace std;
    
    class MyAddress
    {
    private:
        string Country;
        string Province;
        string City;
        string Street;
    
    public:
        string ToString() const;
    };
    
    #endif /* MY_ADDRESS_H */
    

      

    这里有一点要说一下,在Person.h里面并没有使用MyDate*和MyAddress*,而是用了PersonImp*,由PersonImp里面包含MyDate与MyAddress,这样做的好处就是方便统一化管理,要求PersonImp里面的方法与Person的方法是一致的以后Person添加成员变量,可以直接在PersonImp中进行添加了,从而起到了隔离和隐藏的作用,  因为客户端代码大量使用的将是Person,而不必关心PersonImp,用于幕后实现的PersonImp只面向于软件开发者而不是使用者。

    书上是用shared_ptr来管理PersonImp的,使资源管理上更加科学与合理。

    另外,书上也提倡把class x; class xx; class xxx;的声明放至一个名为”xxxfwd.h”的头文件里,比如”datefwd.h”,这个头文件里面只有声明式,而没有具体的类细节。也就是说,对于某个类,比如MyDate,应该分出三个文件,一个是datefwd.h,里面是一些用到的外来的class声明式;一个是MyDate.h里面是MyDate类的结构声明;一个是MyDate.cpp,它与MyDate.h配对,给出具体的实现细节。

  • 相关阅读:
    jquery 触发别的元素事件,并且传递参数
    jquery中的trigger和triggerHandler区别
    jquery 触发别的元素事件
    jquery 禁止页面form提交的通用方法
    对象序列化反序列化例子
    Access数据库访问助手类
    SQL Update 语句中使用别名
    C# 启动和结束进程
    ACCESS查询当天数据的SQL语句(DateDiff函数)
    解决Access数据库 不可识别的数据库格式 ***.accdb
  • 原文地址:https://www.cnblogs.com/zhangkele/p/10556254.html
Copyright © 2011-2022 走看看