适用于场景
当需要对外部user隐藏类内部实现(包括data & APIs)时,要特别注意不同实现方式对内存performance的影响。
本文涉及术语
Virtual API层:开放给用户使用的API层。
Implementation层:实际data & APIs的实现层,对外部user不可见。
Proxy层:实际data & APIs的实现层,对外部user不可见;这是个可选项,在不同实现方式下可能存在。
实现方式一
在Virtual API层增加implementer指针,示例如下:
class Base {
public:
...
virtual void func();
}
class Derived : public Base {
public:
...
virtual void func() override;
private:
DerivedImpl* impl_ = nullptr;
}
在该方式中,Derived类中名为impl_的member data为Implementation层封装类或结构体,无论是指针还是数据对象,其都会导致8Bytes内存需求的增加。同时DerivedImpl数据定义存在泄漏给外部user的风险。
实现方式二
Implementation层继承Virtual API层,data和APIs实现都在Implementation层。
class Base {
public:
...
virtual void func();
}
class Derived : public Base {
public:
...
virtual void func() override;
}
class DerivedImpl: public Derived {
public:
virtual void func() override;
private:
Data mData;
}
注意存在多继承时会导致virtual table ptr引起的8Bytes内存增加。关于该情况举例:
class Base {
public:
...
virtual void func();
}
class Derived : public Base {
public:
...
virtual void func() override;
}
class DerivedImpl_1: public Derived {
public:
virtual void func() override;
private:
Data mData;
}
class Derived_2: public Derived {
public:
...
virtual void func() override;
}
class DerivedImpl_2: public Derived_2, DerivedImpl_1 {
public:
...
virtual void func() override;
private:
Data2 mData2;
}
由于Derived_2是Derived的子类,其数据部分会包含Derived的mData部分,因此在Implementation层就会存在多继承关系。
实现方式三
在实现方式二的基础上增加Proxy层,其结构为Virtual API层排生Proxy层,Proxy层数据为Implementation层指针,并且Proxy层无多继承,Implementaion层无虚继承。
class Base {
public:
...
virtual void func();
}
class Derived: public Base {
public:
...
virtual void func() override;
}
class Derived_2: public Derived {
public:
...
virtual void func() override;
}
class DerivedImpl_1 {
public:
void func();
private:
Data mData;
}
class DerivedImpl_2: public DerivedImpl_1 {
public:
...
void func();
private:
Data2 mData2;
}
class DerivedProxy : public Derived {
public:
...
virtual void func() override;
private:
DerivedImpl_1* impl_ = nullptr;
}
class DerivedProxy_2 : public Derived_2 {
public:
...
virtual void func() override;
private:
DerivedImpl_2* impl_ = nullptr;
}