65,187
社区成员




#include <iostream>
using namespace std;
template <typename T>
class Base
{
public:
void hi()
{
T * pT = static_cast<T*>(this);
pT->sayhi();
}
//protected:
void sayhi()
{
cout<<"hi i am base class"<<endl;
}
};
class A : public Base<A>
{
public:
//protected:
void sayhi()
{
cout<<"hi i am A class"<<endl;
}
};
class B : public Base<B>
{
};
main()
{
A a;
B b;
a.hi(); // prints "hi i am A class"
b.hi(); // prints "hi i am B class"
}
A a;
B b;
a.hi(); // prints "hi i am A class"
b.hi(); // prints "hi i am B class"
写这种代码有什么用?难道这样的代码叫多态?
class Base
{
public:
//基类函数写一次:
void doWork()
{
do1();
do2();
do3();
}
//三个具体执行任务的函数都变成虚函数
virtual void do1(){cout<<"Base Do1;"};
virtual void do2(){cout<<"Base Do2;"};
virtual void do3(){cout<<"Base Do3;"};
};
class A : public Base
{
public:
//同样不需要重写 doWork()
void do1(){cout<<"A Do1;"};
void do3(){cout<<"A Do3;"};
};
class B :public Base
{
void do2(){cout<<"B Do2;"};
void do3(){cout<<"B Do3;"};
};
main()
{
A a;
B b;
a.doWork();//假如是这样使用的话,和模板方式/继承方式没有任何区别.
b.doWork(); //最大的问题也就是虚函数表带来的开销了..
//另外,虚函数的方式还可以实现基类指针调用派生类函数,
// 这也是虚函数真正存在的理由,因为这个无法在编译器决定,
//也就是模板和纯粹继承的方式是实现不了的..
Base *base=new A();
b->doWork();//与 a.doWork() 一样.
//如果一定要用到这种方式,那就只能使用虚函数.
//但是如果不需要用到基类指针调用派生类函数,那就有3种方式可选,
//即上面提到的 普通继承, 模板 , 虚函数
//三者各有优缺点,看个人需要吧...
}
---------
总结一句:
这种模板的使用方式,其实就是所谓的"编译器多态",即,在编译期间可以让基类调用派生类的函数!!(而不是像虚函数那样在运行期调用!)
template <typename T>
class Base
{
public:
// 假如一个工作有do1,do2,do3 这3个工序,但是不同的类型的具体做法不同...
// 不过类 Base,A,B对这3道工序的详细情况有些不同...
// 在模板的情况下,你只需要在基类里面写一次:
void doWork()
{
T * pT = static_cast<T*>(this);
pT->do1();
pT->do2();
pT->do3();
}
void do1(){cout<<"Base Do1;"};
void do2(){cout<<"Base Do2;"};
void do3(){cout<<"Base Do3;"};
};
class A : public Base<A>
{
public:
// 派生类里面不需要再重复写这个 dowork() 函数了...
// 只需要把对应与Base()的不同的那道工序写出来就可以了..
void do1(){cout<<"A Do1;"};
void do3(){cout<<"A Do3;"};
};
// 实际使用的时候: A a;a.dowork() 会依次调用 A::do1() , Base::do2() , A::do3();
//..
class B : public Base<B>
{
void do3(){cout<<"B Do3;"};
};
但是,如果没有采用模板(也没有采用虚函数),你要实现这种方式,必须为A,B类重写那个dowork()函数
class Base
{
public:
void doWork()
{
do1();
do2();
do3();
}
void do1(){cout<<"Base Do1;"};
void do2(){cout<<"Base Do2;"};
void do3(){cout<<"Base Do3;"};
};
class A : public Base<A>
{
public:
void doWork()
{
do1();
do2();
do3();
}
void do1(){cout<<"A Do1;"};
void do3(){cout<<"A Do3;"};
};
class B : public Base<B>
{
void doWork()
{
do1();
do2();
do3();
}
void do2(){cout<<"B Do2;"};
void do3(){cout<<"B Do3;"};
};
然后,假设你有了很多这种派生类,然后,发现工序突然变了,变成 do2(),do3(),do1() ,然后,所有派生类你就自己一个一个慢慢修改吧...
如果采用这种模板机制,你只需要修改基类的一个函数就可以了...
(当然,也可以采用虚函数的方式代替)
另外,虚函数的出现,不就是解决这类问题的吗? 由基类决定函数工序顺序,由派生类来具体的执行任务...
而这种模板机制,只不过把虚函数的这个功能由运行期提前到编译器决定,减少了虚函数的调用开销罢了...
大概就这么多了,其他就由楼上楼下补充了....