静多态,动多态对比
来源:互联网 发布:数控车床左螺纹编程 编辑:程序博客网 时间:2024/06/16 07:59
静态多态 泛型编程里的常用手法 STL里屡见不鲜。
静多态的静态特性:
所有的类型必须在编译期确定
静多态,动多态对比
通过继承实现的多态是绑定的和动态的:
1,绑定:对于参与多态行为的类型,它们的接口在公共基类中就预先确定
2,动态:接口的绑定是运行期(动态)完成的
通过模式实现的多态是非绑定的和静态的:
1,非绑定:对于参与多态行为的类型,它们的接口没有预先确定
1, 静态:接口的绑定是编译期(静态)完成的
优点
1,相比动多态,静多态有更好的安全性:
因为静多态在编译期对所有的绑定操作进行检查【若把一个错误类型对象插入到容器,编译期可以检查这个错误。】。
2、避免虚指针的内存损耗以及虚函数调用运行效率损耗
缺点:
1、因为编译时会加入类型的确定,代码尺寸会稍稍大一点
2、无法对多态对象统一处理,多态性稍有折扣
例子
动多态:虚函数,继承实现
void mydraw(base const&obj)//base是一个抽象基类
{
obj.draw();
}
静多态:模板实现
例子1:演示静态多态
template<class mybase>
void mydraw(mybase const&obj)//mybase是模板参数
{
obj.draw();
}
line l;
circle c;
mydraw(l);//mydraw<line>(mybase&)--->line::draw()
mydraw(c);//mydraw<circle>(mybase&)--->circle::draw()
*****************************************************************
例子2:演示 静态多态+traits技法
此例子原地址:http://blog.csdn.net/pongba/article/details/82783
假设一所大学的注册系统提供了一个注册函数:
template<class T>
void Register(T person)
{
Register(person, typename T::person_tag());
};
而对于注册者有以下几种标识:
struct student_tag{};
struct teacher_tag{};
还有Register的几个供内部使用的重载版本:
template<class T> void Register(T p, student_tag){...}// 注册学生
template<class T> void Register(T p, teacher_tag){...}// 注册教师
并规定学生类一定要在内部typedef student_tagperson_tag,教师类typedef teacher_tag person_tag,
这样,当传给起初的那个Register的对象为学生类对象时,typenameT::person_tag()其实就构造了一个student_tag对象,
从而激发函数重载,调用Register内部版本的template<class T> voidRegister(T p,student_tag)版本。其他情况亦均有对应。
这是泛型编程里的常用手法(静态多态),STL里屡见不鲜。
例子3:演示静态多态+动态多态
template<typename T>
class Category2
{
protected:
static string m_strName;
public:
virtual void SayCatName()
{
T* pT = static_cast<T*>(this);
pT->SayCatName();
}
};
class Car2 : public Category2<Car2>
{
public:
virtual void SayCatName()
{
cout << m_strName << endl;
}
};
string Car2::m_strName = "Car2";
class House2 : public Category2<House2>
{
public:
virtual void SayCatName()
{
cout << m_strName << endl;
}
};
string House2::m_strName = "House2";
// test Template
Category2<Car2>* pCar2 = new Car2();
pCar2->SayCatName();
delete pCar2;
pCar2 = NULL;
Category2<House2>* pHouse2 = new House2();
pHouse2->SayCatName();
delete pHouse2;
pHouse2 = NULL;
补充:type_traits
template<classT> // T表示接受的是何种动物
voidAcceptAnimals(T animal)
{
... //dosomething
};
想将猫和狗分开处理(毕竟饲养一只猫和饲养一只狗并不相同。他们可能会为狗买一根链子,而温顺的猫则可能不需要)。
方法一:虚函数,但不能用于模板函数
方法二:获取类型T的特征(trait),并按照不同的特征来采用不同的策略
步骤:
1, 每个类的型别定义,即typedef的空类,目的是激发函数重载。约定所有的动物类(如class Cat,class Dog)都必须在内部typedef一个表明自己身份的类型。作为标识的类型如下:
structcat_tag{}; //这只是个空类,目的是激发函数重载
structdog_tag{}; //同上
2, 类内部的typedef定义
所有狗类都必须像这样:
class Dog
{
public:
// 类型(身份)标志,表示这是狗类,如果是猫类则为typedef cat_tag type;
typedef dog_tag type;
..
}
3, 内层函数增加型别定义的类作为参数
//第二个参数为无名参数,只是为了激发函数重载
template<classT>
void Accept(Tdog,dog_tag)
{...}
template<classT>
void Accpet(Tcat,cat_tag) // 同上
{...}
4,外层函数
template<classT>
void Accept(Tanimal) //这是向外界提供的唯一接口
{
//如果T为狗类,则typename T::type就是dog_tag,那么typenameT::type()就是创建了一个dog_tag类的临时对象,根据函数重载的规则,
这将调用Accept(T,dog_tag),这正是转向处理狗的策略。
//如果T为猫类,则typename T::type为cat_tag,由上面的推导,这将调用Accept(T,cat_tag),即转向处理猫的策略,
typename 关键字告诉编译器T::type是个类型而不是静态成员。
Accept(animal,typenameT::type()); // #1
}
注:所有类型推导,函数重载,都在编译期完成
typenameT::type其实就是traits,只不过少了一层封装而已,如果像这样作一些改进:
template<typenameT>
struct AnimalTraits
{
typedef T::typetype;
};
于是,#1处的代码便可以写成:
Accept(animal,typename AnimalTraits<T>::type());
其他traits技法参考博文STL系列《《STL源码剖析》traits技法》
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
- 静多态,动多态对比
- 对比
- 对比
- 对比
- 对比...
- 对比
- 对比
- 对比
- 对比
- 时间对比
- 对比SET
- 密码对比
- 对比同行
- 围脖对比
- 算法对比
- 博客对比
- 对比keys
- drawable对比
- PostgreSQL数据库中的表和数据(Tables & Data)
- 编辑文章 - 博客频道 - CSDN.NET
- 上供货商公司工会手工活
- 主线程
- SQL on Hadoop系统的最新进展
- 静多态,动多态对比
- 迷宫算法
- android视频监控的解决方案探讨
- 数据库开发(22)高级事务处理
- Spring管理Action并在Action中开启事务,在继承ModelDriven时无法在JSP中访问Action属性
- pxe网络引导安装linux_mint自定义镜像环境
- SQLServer变量_循环
- 4G高屏占比 华为MediaPad X1平板电脑发布
- EASY_PAT_ZJU_1046 求循环数字公路中两个出口的最短距离