需求
cpp impl ?
解决
impl 使用接口类有两种方式:
- 接口类只是作为一个壳,需要什么都是直接调用原来的类来实现
- 接口类是使用虚函数,实现类通过继承来实现
代理类
代理类非常简单,下面这个 WeightProxy
就是壳,具体的实现都在 Weight
里面。
#ifndef WEIGHTPROXY_H
#define WEIGHTPROXY_H
#include <string>
#include <memory>
class Weight;
class WeightProxy
{
public:
WeightProxy();
~WeightProxy();
std::string GetInfo();
std::unique_ptr<Weight> m_proxy;
};
#endif // WEIGHTPROXY_H
#include "Weightproxy.h"
#include "Weight.h"
WeightProxy::WeightProxy()
: m_proxy(new Weight())
{
}
WeightProxy::~WeightProxy() = default;
std::string WeightProxy::GetInfo() {
return m_proxy->GetInfo();
}
#include <iostream> // std::streambuf, std::cout
#include "Weightproxy.h"
int main () {
WeightProxy w;
std::cout << w.GetInfo() << std::endl;
return 0;
}
有以下几个注意点:
- 如果使用指针或者引用可以实现,就不要用Object,因为定义某类型的Object 需要类型的定义式,而前者只需要声明.
- 尽量用声明替换定义,当你声明一个函数,并且他用到某个class时,不需要该class的定义,即使函数是 Object传递参数或者返回值. 注意了,变量只有是指针我们才能使用声明,但是函数却没有这个限制,即使是对象也可使用声明,本质是函数编译不依赖于实现,但是调用函数之前,Test定义式一定要存在,重要的目的是把这种include形式传递到客户调用函数的那个文件中,将类型定义和客户端依赖去除,说白了库的提供者一个类中会提供很多函数,因为库的提供者选择 class形式,那么对于客户端只有需要 知道Test的具体定义的才去包含Test头文件,减少不必要的依赖
- 为声明式和定义式提供不同头文件.因为定义式里面包含的头文件的真实实现,客户端不应该自己手工class声明,而是库实现侧自己提供两种头文件一个是声明、一个是定义声明文件就是给客户端像include的形式使用声明,也就是声明文件的内容就仅仅是 class Test
虚函数继承
这种虚函数继承,一般会搭配工厂模式。缺点是有虚函数开销和二进制兼容的问题。
// network.h
// 版本3
class NetworkV3 {
public:
virtual int Send(const std::string str) = 0;
virtual int Recv(std::string &str) = 0;
// 创建和销毁函数
static NetworkV3* New();
static void Delete(NetworkV3 *net);
};
// network.cpp
// 版本3
class NetworkV3Impl final : public NetworkV3 {
public:
int Send(const std::string str) override {
std::cout << "NetworkV3Impl::Send: " << str << std::endl;
return str.size();
}
int Recv(std::string &str) {
str = "ok";
std::cout << "NetworkV3Impl::Recv: " << str << std::endl;
return str.size();
}
};
// 创建和销毁函数
NetworkV3* NetworkV3::New() {
return (new NetworkV3Impl());
}
void NetworkV3::Delete(NetworkV3 *net) {
delete (NetworkV3Impl*)net;
}
总结
- 使用IMPL方式来较少类之间的依赖,减少编译时间
- 变量可以使用指针,一大推变量使用结构体,类可以使用一个托管类,大致这三类型来实现减少依赖。
- 其实本质上来说,头文件之间就不应该有定义的依赖,所以java中统一使用了指针,实现cpp中才是真正包含所有具体定义,头文件是用来声明这个类长什么样子,实现cpp中用来实现这个类内部怎么实现的。