您的位置:首页 > 编程语言 > C语言/C++

Step By Step(C++模板和继承)

2012-09-10 09:27 489 查看
[b]一、命名模板参数:[/b]

有些高级脚本语言,如Perl、PL/SQL等,他们的函数参数在调用时都支持命名参数,既在调用时可以不按照顺序传递参数,而是p可以按照参数的名字传递。先看下面的代码示例:
template<typename Policy1 = DefaultPolicy1,
typename Policy2 = DefaultPolicy2,
typename Policy3 = DefaultPolicy3,
typename Policy4 = DefaultPolicy4>
class BreadSlicer {
... ...
}
上面的模板类含有4个模板参数,如果要想指定其中的某个参数不为缺省参数,那么也必须同时指定其之前的所有模板参数,如:
BreadSlicer<DefaultPolicy1,DefaultPolicy2,Custom>,然而我们更希望使用这样的调用形式:BreadSlicer<Policy3 = Custom>。下面将给出一些具体的实现,请务必留意代码中的关键性注释:

#include <stdio.h>
#include <typeinfo>
#include <conio.h>

//先定义出不同的策略类。
class DefaultPolicy1 {};
class DefaultPolicy2 {};
class DefaultPolicy3 {};
class DefaultPolicy4 {};

//该类将会是所有Policy Class的基类。他提供了缺省的四个Policy的类型重定义。
//因此在缺省情况下,这四个Policy将会是BreadSlicer的四个Policy。
class DefaultPolicies {
public:
typedef DefaultPolicy1 P1;
typedef DefaultPolicy2 P2;
typedef DefaultPolicy3 P3;
typedef DefaultPolicy4 P4;
};

//这里之所以给出中间类DefaultPolicyArgs,同时又让该类以虚拟继承的方式继承
//DefaultPolicies,一是为了避免后面在多重继承同一基类时而导致的二义性,同时
//也是为了方便后面其他类的继承。
class DefaultPolicyArgs : virtual public DefaultPolicies {
};

//这里之所以有第二个常量模板参数,是为了避免重复继承相同的基类。
template<typename Base, int D>
class Discriminator : public Base {
};

//在这里,如果没有Discriminator的常量模板参数,将极有可能导致继承同一个基类。
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:
//在该类后面的实现中,不要直接使用模板参数,而是要使用Policies::P1, P2, P3, P4等。
typedef PolicySelector<PolicySetter1,PolicySetter2,PolicySetter3,PolicySetter4> Policies;
void DoTest() {
printf("Policies::P1 is %s\n",typeid(Policies::P1).name());
printf("Policies::P2 is %s\n",typeid(Policies::P2).name());
printf("Policies::P3 is %s\n",typeid(Policies::P3).name());
printf("Policies::P4 is %s\n",typeid(Policies::P4).name());
}
};

template<typename Policy>
class Policy1_is : virtual public DefaultPolicies {
public:
typedef Policy P1;   //改写DefaultPolicies中的基于P1的typedef。
};

template<typename Policy>
class Policy2_is : virtual public DefaultPolicies {
public:
typedef Policy P2;   //改写DefaultPolicies中的基于P2的typedef。
};

template<typename Policy>
class Policy3_is : virtual public DefaultPolicies {
public:
typedef Policy P3;   //改写DefaultPolicies中的基于P3的typedef。
};

template<typename Policy>
class Policy4_is : virtual public DefaultPolicies {
public:
typedef Policy P4;   //改写DefaultPolicies中的基于P4的typedef。
};

class CustomPolicy {};

int main() {
BreadSlicer<Policy3_is<CustomPolicy> > bc;
bc.DoTest();
getch();
return 0;
}
//Policies::P1 is class DefaultPolicy1
//Policies::P2 is class DefaultPolicy2
//Policies::P3 is class CustomPolicy
//Policies::P4 is class DefaultPolicy4


在上面的例子中一个非常重要的特点是,所有的模板实参都是DefaultPolicies的派生类。在声明BreadSlicer对象时,不同的派生类将覆盖不同的DefaultPolicies中的typedef。

[b]二、递归模板模式:[/b]

这是一种通用的模板设计模式,即派生类将本身作为模板参数传递给基类,如:
template<typename DerivedT>
class Base {
... ...
};
class MyDerived : public Base<MyDerived> {
... ...
};
基于这种模式,有一个非常著名的用例,即[MeyersCounting],是《Effective C++》的作者Scott Meyers所设计的。通过继承以下代码中的基类,所有的派生类便可实现类实例计数的功能。在下面的基类中,将包含一个表示对象计数的静态成员,同时还会在基类构造的时候递增该值,并在析构的时候递减该值,见如下代码示例:

#include <stdio.h>
#include <conio.h>

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 liveCount() {
return ObjectCounter<CountedType>::count;
}
};

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

//C++编译器会根据模板参数的不同实例化不同类型的类对象,因此模板参数不同,所使用的静态成员也是不同的。
class MyClass : public ObjectCounter<MyClass> {
};

int main() {
MyClass mc1;
printf("The count of MyClass is %d\n",MyClass::liveCount());
{
MyClass mc2;
printf("The count of MyClass is %d\n",MyClass::liveCount());
}
printf("The count of MyClass is %d\n",MyClass::liveCount());
getch();
return 0;
}
//The count of MyClass is 1
//The count of MyClass is 2
//The count of MyClass is 1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: