Effective C++(七):inline关键字, 降低文件间依存关系


一、知识点一

将函数声明为内联一共有两种方法,一种是为其显式指定inline关键字,另一种是直接将成员函数的定义式写在类中,如下所示:

class Person {
public:
    ...
    int Age() const { return theAge; }  // 隐式声明为 inline
    ...
private:
    int theAge;
};

在inline诞生之初,它被当作是一种对编译器的优化建议,即将“对此函数的每一个调用”都以函数本体替换之。但在编译器的具体实现中,该行为完全被优化等级所控制,与函数是否内联无关。

在现在的 C++ 标准中,inline作为优化建议的含义已经被完全抛弃,取而代之的是“允许函数在不同编译单元中多重定义”,使得可以在头文件中直接给出函数的实现。

在 C++17 中,引入了一个新的inline用法,使静态成员变量可以在类中直接定义:

class Person {
public:
    ...
private:
    static inline int theAge = 0;  // since C++17
};

在之前的C++标准中,静态变量需要在类外部进行初始化。

二、将文件间的编译依存关系降至最低

C++ 坚持将类的实现细节放置于类的定义式中,这就意味着,即使你只改变类的实现而不改变类的接口,在构建程序时依然需要重新编译。这个问题的根源出在编译器必须在编译期间知道对象的大小,如果看不到类的定义式,就没有办法为对象分配内存。也就是说,C++ 并没有把“将接口从实现中分离”这件事做得很好。

为了更好地将类中接口的定义和实现分割开来,我们可以实现两个类,一个类负责暴露接口,一个类负责接口的具体实现:

// person.hpp 负责声明类

class PersonImpl;

class Person {
public:
    Person();
    void Print();
    ...
private:
    std::shared_ptr<PersonImpl> pImpl;
};

// person.cpp 负责实现类

class PersonImpl {
public:
    int data{ 0 };
};

Person::Person() {
    pImpl = std::make_shared<PersonImpl>();
}

void Person::Print() {
    std::cout << pImpl->data;
}

这样,假如我们要修改Person的private成员,就只需要修改PersonImpl中的内容,而PersonImpl的具体实现是被隐藏起来的,对它的任何修改都不会使得Person客户端重新编译,真正实现了“类的接口和实现分离”。在这里PersonImpl也被称作是句柄类

三、接口类

实现类额接口和实现分离的另外一种方法是接口类。也就是一个只包含若干接口的类。

class Person {
public:
    virtual ~Person() {}
    virtual void Print();
    static std::shared_ptr<Person> Create();
};

但是此时此刻 Create 函数还无法使用,需要在派生类中给出 Person 类的函数的具体实现。
class RealPerson : public Person {
public:
RealPerson(…) {…}
virtual ~RealPerson() {}
void Print() override {…}
private:
int date{0};
};

在我们实现了RealPerson的定义以后,我们再完成 Create 函数的定义
static std::shared_ptr Person::Create() {
return std::make_shared();
}
毫无疑问的是,句柄类和接口类都需要额外的开销,句柄类通过 Person 类中的指向PersomImpl的指针来获得对象数据,增加一层间接访问,指针大小和动态分配内存带来的开销; 而接口类会增加存储虚表指针和实现虚函数跳转带来的开销。

如果这些开销太大了,就应该以具象类代替句柄类和接口类。


  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值