Effective C++(降低文件依赖)

编译依赖

例子

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 theName;
    Date theBirthDate;
    Address theAddress;
};

这个代码无法通过编译,因为缺少 Date,Address,string的定义。需要头文件

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

但是这样就构建了依存关系。编译依存关系。 如果有的头文件改变
与之关联的文件都得重新编译。对于大型项目是十分可怕的。

想法一,前置声明

namespace std{
    class string; //前置声明(不对,见缺点1)
}

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 theName;
    Date theBirthDate; // 即便是前置声明,这里编译器还是需要知道Date的大小。
    Address theAddress;// 即便是前置声明,这里编译器还是需要知道Address的大小。所以不成功,依赖还是存在。
};

缺点

  1. string是一个typedef,正确的前置声明很复杂。因为涉及到templates。但是这不重要。因为你根本就不应该使用前置生命来声明标准库的对象。因为使用include来完成任务。

想法二,使用指针指向实现

#include <string>
#include <memory>

class PersonImpl;
class Date;
class Address;

class Person{
public:
  // 函数本身只需要声明式即可。
    Person(const std::string& name, const Date& birthday, const Address& addr); //这里用的全是reference所以是不需要定义式的。只需要声明式。
    std::string name() const;
    std::string bithDate() const;
    std::string address() const;
private:
    std::tr1::shared_ptr<PersonImpl> pImpl;
};

如此以来,使用Person的客户代码就不会依赖于PersonImpl的实现细节和Address以及Date的实现细节。这就实现了依赖解绑。

关于依赖

  1. 如果可以使用object reference和object
    pointer可以实现目的。就不要使用objects.

    (原因,你只需要声明就可以定义出指向该类型的reference和pointer但是,如果定义objects就需要用到定义式。

  2. 如果可以,尽量使用class声明式取代class定义式。

    class Date;                    //声明式
    Date today();           //不需要定义式,只需要声明式
    void clearAppointments(Date d) //不需要定义式,只需要声明式
    

    当声明函数的时候,只需要对象的声明式即可,即便参数和返回值,是按照by
    value的方式传递的。

  3. 为声明式,和定义式提供不同的头文件。比如

    #include "datefwd.h"
    Date today();           //不需要定义式,只需要声明式
    void clearAppointments(Date d) //不需要定义式,只需要声明式
    

如何实现的

#include "PersonImpl.h" //必须在实现文件中引入这个定义头文件

Person::Person(const std::string& name, cosnt Date& birthday, const Address& addr)
    :pImpl(new PersonImpl(name, birthday, addr))
{}

std::string Person::name() const
{
    return pImpl->name();
}

想法三,使用抽象类

//声明式,在这里即可。new也只需要声明式。
class Person{
public:
    virtual ~Person();
    virtual std::string name() const = 0;
    virtual std::string birthDate() const = 0;
    virtual std::string address() const = 0;
    static std::tr1::shared_ptr<Person> create(const std::string& name, const Date& birthday, const Address& addr)
    {
        return std::tr1::shared_ptr<Person>(new RealPerson(name, birthday, addr));
    }
};

class RealPerson:public Person{
public:
    RealPerson(const std::string& name, const Date& birthday, const Address& addr)
        :theName(name), theBirthDate(birthday), theAddress(addr)
    {}

    virtual ~RealPerson(){}
    std::string name() const;
    std::string birthDate() const;
    std::string address() const;

private:
    std::string theName;
    Date theBirthDate;
    Address theAddress;
};

Notes

  1. export
    允许将template的定义式和声明式分开。放在不同文件中,但是不是所有的编译器都实现了这个东西。

使用指针来降低文件依赖和使用虚基类来降低文件依赖的缺点

  1. 丧失若干速度。你要付出一定的内存。因为需要额外的指针间接访问实际的调用函数。
  2. 但是去请记住2-8原则,80%的虚函数指针可能都没有被使用到。
  3. 你应该在程序实现的过程中动态调整是否使用handle classes和interface
    classes.速度如果有影响,则修改关键的20%代码直接使用定义式。
  4. inline可以帮助handle classes和interface classes实现它们应有的目的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值