Item 31:最小化文件之间的编译依赖 Effective C++笔记
曾听老师讲过,每天上班的第一件事就是下载最新代码开始编译,然后可以有半个小时去喝杯咖啡。。。 这是C++特殊的一点,即使你在保持接口不变的情况下只改了类的内部实现,其他的项目文件仍然可能需要重新编译。 C++的Class不仅规约了外部接口,也给出了内部实现: class Person{
public:
// 外部接口
Person(const string& name);
string name() const;
private:
// 内部实现
string _name;
Date _birthday;
};
基于 include<string>
include"date.h"
这些 你可能会想到,在 string;
Date;
Person{
...
};
Person p;
编译通过不了!首先 使用指针代替对象 一个去除编译依赖的办法是:依赖项使用指针而不是对象,同时依赖于类的声明而非定义。比如我们把 Person{
...
private:
Date* _birthday;
}
编译器为 Date;
Date d;
void func(Date d);
虽说对象作为函数参数还是传递引用比较好(见Item 20:传递常量引用比传值更好),但即使你传递的是对象,也不需要给出它的内部实现。 单独地提供声明 既然我们希望依赖于声明而非定义,那么我们需要为每个类单独地提供声明文件,和定义文件。 比如 // file: datefwd.h
Date;
// file: date.h
Date{
...
};
我们在 使用句柄类 C++中接口声明和内部实现必须同时引入, 但在Java等语言中便不存在这个问题。因为所有对象都是引用,比如 public:
Person(string& name);
string name() private:
shared_ptr<PersonImpl> pImpl;
};
Person::Person(string& name): pImpl(new PersonImpl(name)){}
string Person::name(){
return pImpl->name();
}
相当于把实现放到了另外一个类中 使用接口类还记得虚函数吗?除了句柄类,还有另外一个方式来移除编译依赖:接口类。在Java或C#中有接口的概念, 一个类可以实现若干个接口。但在C++中只有类的概念,但我们可以用只包含虚函数的类来定义一个接口: public:
virtual ~Person();
virtual string name() const = 0;
virtual string birthday() const = 0;
};
这个 比如 static shared_ptr<Person> create(string& name);
};
shared_ptr<Person> Person::create(string& name){
return shared_ptr<Person>(new RealPerson(name));
}
...
shared_ptr<Person> p(Person::create("alice"));
总结最小化编译依赖的一般做法是依赖于声明而非定义,这个想法可以通过句柄类或接口类来实现。库的声明应当包括“完整的”和“只有声明的”两种形式。 接口类和句柄类的设计隐藏了类的实现细节,减小了实现细节的改动对客户的影响。 但无论是接口类还是句柄类,都会造成一些代价:多一个 确实有人会因为这些代价而拒绝使用这些先进的技术,你会发现很难说服他们。这一点即便是Scott Meyers也没有办法:
除非注明,本博客文章均为原创,转载请以链接形式标明本文地址:http://harttle.com/2015/08/29/effective-cpp-31.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |