继承情景
我们知道一个空的类,也就是其内部没有非静态数据成员,没有虚指针(包括指向虚函数表和虚基类子对象的指针),它的大小通常为1,当然在某些对齐要求严格系统上可能是另一个数(通常是4),如果空类被继承,那么派生类的大小会怎么样呢?一个支持C++标准和EBO的编译器对此会进行空基类的优化,也就是不给空的基类子对象分配空间,换句话说,空基类子对象的地址和其派生类实例的地址是相同的。从编译器实现的角度来看,需要考虑继承时的不同情况,下图中P表示父类,C表示子类,圆形表示空类,矩形表示非空类。单继承EBO情况如下图所示
EBO-1反映的是空类派生自空基类,EBO-2反映的是非空类派生自空基类,EBO-3、EBO-4反映的是在继承链中,对空基类的优化能不能传递到后代中。多继承EBO如下图所示
EBO-5反映的是空类派生自两个空基类,EBO-6反映的是非空类派生自两个空基类,EBO-6反映的是空类派生自一个非空基类和一个空基类,EBO-7反映的是非空类派生自一个非空基类和一个空基类。以上8种情况,不论是单继承还是多继承,一个完全支持EBO的编译器就应该能把空基类部分都优化掉。
优化应用
由于空基类优化技术节省了对象不必要的空间,提高了运行效率,因此成为某些强大技术的基石,基于类型定义类如stl中的binary_function、unary_function、iterator、iterator_traits的实现复用;基于策略类如内存管理、多线程安全同步的实现复用。当某个类存在空类类型的数据成员时,也可考虑借助EBO优化对象布局,例如下
1
template<typename T1,typename T2>
2
class EBO
3![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
4
private:
5
T1 m_t1;
6
T2 m_t2;
7
};
当T1和T2为空类时,可以改进如下
1
template<typename T1,typename T2>
2
class EBO : T1, T2
3![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
4
};
更进一步,如果T1或T2为非类类型,如基本内建类型、函数指针等;或T1和T2类型相同时,则直接继承它们会导致编译错误,怎么办呢?这时可以添加一个中间层来解决,代码如下
1
template<typename T1,typename T2,bool isSame,bool isFirstEmpty,bool isSecondEmpty>
2
class EBO_IMPL;
3![](/Images/OutliningIndicators/None.gif)
4
template<typename T1,typename T2>
5
class EBO_IMPL<T1,T2,false,false,false>
6![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
7
T1 m_t1;
8
T2 m_t2;
9
};
10![](/Images/OutliningIndicators/None.gif)
11
template<typename T1,typename T2>
12
class EBO_IMPL<T1,T2,false,true,true> : T1,T2
13![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
14
};
15![](/Images/OutliningIndicators/None.gif)
16
template<typename T1,typename T2>
17
class EBO_IMPL<T1,T2,false,true,false> : T1
18![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
19
T2 m_t2;
20
};
21![](/Images/OutliningIndicators/None.gif)
22
template<typename T1,typename T2>
23
class EBO_IMPL<T1,T2,false,false,true> : T2
24![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
25
T1 m_t1;
26
};
27![](/Images/OutliningIndicators/None.gif)
28
template<typename T1,typename T2>
29
class EBO_IMPL<T1,T2,true,false,false>
30![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
31
T1 m_t1;
32
T2 m_t2;
33
};
34![](/Images/OutliningIndicators/None.gif)
35
template<typename T1,typename T2>
36
class EBO_IMPL<T1,T2,true,true,true> : T1
37![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
38
T2 m_t2;
39
};
40![](/Images/OutliningIndicators/None.gif)
41
template<typename T1,typename T2>
42
class EBO : EBO_IMPL<T1,T2,boost::is_same<T1,T2>::value,boost::is_empty<T1>::value,boost::is_empty<T2>::value>
43![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
44
};
为了简便,直接使用了boost中的is_same,is_empty元函数来判断类型的属性,实际上boost中已经实现了EBO的选择运用工具即compressed_pair类模板,研究其源码可发现,该工具充分考虑到了T1和T2实际类型的各种情况,is_empty的判断是运用sizeof来比较类型大小确定的。替换compressed_pair后,代码如下
1
template<typename T1,typename T2>
2
class EBO: boost::compressed_pair<T1,T2>
3![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
4
};
posted on 2011-07-10 12:58
春秋十二月 阅读(2600)
评论(0) 编辑 收藏 引用 所属分类:
Opensrc