模板与继承

 @[TOC]模板与继承

命名模板参数

命名模板参数主要利用了C++继承中的一个规则,子类重定义,会隐藏基类中定义:

class DefaultPolicy1
{
public:
	void print()
	{
		cout << "Policy 1" << endl;
	}
};

class DefaultPolicy2
{
public:
	void print()
	{
		cout << "Policy 2" << endl;
	}
};

class DefaultPolicies
{
public:
	typedef DefaultPolicy1 P1;
	typedef DefaultPolicy2 P2;
};

class DefaultPolicyArgs : virtual public DefaultPolicies
{

};

class Policy1_is : virtual public DefaultPolicies
{
public:
	typedef DefaultPolicy1 P2;
};

class Policy2_is : virtual public DefaultPolicies
{
public:
	typedef DefaultPolicy2 P1;
};

class PolicySelector : public DefaultPolicyArgs, public Policy2_is
{
};

int main()
{
	PolicySelector::P1 p;
	p.print();
}

上面例子中,Policy2_is重定义了P1,所以在PolicySelector中P1是DefaultPolicy2,结果输出:Policy 2。

DefaultPolicyArgs 类似乎是毫无意义的。如果删除DefaultPolicyArgs定义,PolicySelector定义改为:

class PolicySelector : public DefaultPolicies, public Policy2_is
{
};

编译器会提示PolicySelector::P1不明确。

在上面例子中加入模板:

class DefaultPolicy1
{
};

class DefaultPolicy2
{
};

class DefaultPolicy3
{
};

class DefaultPolicy4
{
};

class SpecialPolicy
{
};

class DefaultPolicies
{
public:
	typedef DefaultPolicy1 P1;
	typedef DefaultPolicy2 P2;
	typedef DefaultPolicy3 P4;
	typedef DefaultPolicy3 P4;
};

class DefaultPolicyArgs : virtual public DefaultPolicies
{
};

template <typename Policy>
class Policy_is1 : virtual public DefaultPolicies
{
public:
	typedef Policy P1;
};

template <typename Policy>
class Policy_is2 : virtual public DefaultPolicies
{
public:
	typedef Policy P2;
};

template <typename Policy>
class Policy_is3 : virtual public DefaultPolicies
{
public:
	typedef Policy P3;
};

template <typename Policy>
class Policy_is4 : virtual public DefaultPolicies
{
public:
	typedef Policy P4;
};

typename <typename Base, int D>
class Discriminator : public Base
{
};

template <typename Setter1, typename Setter2, typename Setter3, typename Setter4>
class PolicySelector : public Discriminator<Setter1, 1>,
					   public Discriminator<Setter2, 2>,
					   public Discriminator<Setter3, 3>,
					   public Discriminator<Setter4, 4>
{
};

template <typename PolicySetter1 = DefaultPolicyArgs,
		  typename PolicySetter2 = DefaultPolicyArgs,
		  typename PolicySetter3 = DefaultPolicyArgs,
		  typename PolicySetter4 = DefaultPolicyArgs>
class BreadSlicer
{
public:
	typedef PolicySelector<PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4> Policies;
};

现在,使用BreadSlicer可以直接指定任何一个模板实参。如果定义一个BreadSlicer<Policy3_is >变量,那么PolicySelector相当于继承了DefaultPolicyArgs和Policy3_is,所以P3被重定义为SpecialPolicy类。模板Discriminator的引用是为了避免继承同一个类。

空基类优化EBCO

class EmptyClass
{
};

一般地,定义了一个EmptyClass这样的空类,其对象的大小也不会为0,也就是说需要分配内存。
但是C++规定,当空类作为基类时,只要不会与同一类型的另一个对象或者子对象分配在同一地址,就不需要为其分配内存。这就是空基类优化。

class Empty
{
};

class EmptyToo : public Empty
{
};

class EmptyThree : public EmptyToo
{
};

在支持空基类优化的编译器环境中,上面代码中的3个类大小相同,但都不为0。也就是说EmptyToo和EmptyThree的基类都不占内存。C++环境中不存在真正意义上不占内存的类,空基类优化是针对空类作为基类时,在子类中是否需要分配内存的一个规则。

class NonEmpty : public Empty, public EmptyToo
{
};

NonEmpty类中的基类Empty和EmptyToo都是占内存。否则,NonEmpty中的Empty直接基类和EmptyToo中的Empty间接基类地址就会重合,这违反了空基类优化规则。

下面是空基类优化的一个应用例子(更多情况可百度boost.compressed_pair):

template <typename CustomClass>
class Optimizable
{
private:
	CustomClass info;
	void* storage;
};

其中CustomClass一定是类类型,且可能为空,那么可以优化:

template <typename CustomClass>
class Optimizable
{
private:
	BaseMemberPair<CustomClass, void*> info_and_storage;
};

template <typename Base, typename Member>
class BaseMemberPair : private Base
{
private:
	Member member;

public:
	BaseMemberPair(Base const &b, Member const &m) : Base(b), member(m)
	{}

	Base const& first() const
	{
		return (Base const&)*this;
	}

	Base& first()	
	{
		return (Base&)*this;
	}
	
	Member const& second() const
	{
		return this->member;
	}

	Member& second()	
	{
		return this=>member;
	}
};

奇特的递归模板模式CRTP

CRTP的主要特点是派生类将自身作为模板参数传给基类。

下面例子是一个数某个类对象个数的类模板。当需要计算某个类对象个数时,只要继承ObjectCount模板就可以,模板实参自然是类本身:

template <typename CountedType>
class ObjectCounter
{
private:
	static size_t count;

protected:
	ObjectCounter()
	{
		++ObjectCounter<CountedType>::count;
	}

	ObjectCounter(ObjectCounter<CountedType> const&)
	{
		++ObjectCounter<CountedType>::count;
	}

	~ObjectCounter()
	{
		--ObjectCounter<CountedType>::count;
	}

public:
	static size_t live()
	{
		return ObjectCounter<CountedType>::count;
	}
};

template <typename CountedType>
size ObjectCounter<CountedType>::count = 0;

CRTP把类的功能提取出来,放到一个依赖于自身的模板类中实现,再继承模板类重新获取该功能。如果只有一个类需要,或者只有一个类通过该模式能够实现功能,那该模式是没有意义。CRTP的本质是为了泛化,所以为了不失一般性,一般只提取仅能用作成员函数的接口(构造函数、析构函数、下标运算符Operator[]等)的功能。换句话说,如果有一个功能是在仅能用作成员函数的接口中实现的,并且意图把功能应用到其他类时,CRTP是一个不错的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值