多态的前提条件部分整理
- 子类继承
- 父类指针或者引用
- 虚函数(virtual <类名><函数名>(参数))
在纯面向对象语言中,所有的函数都是多态的,而像C++这样的混合语言,函数既可以是多态的也可以是非多态的,这要由绑定的实际是编译时刻还是运行时刻来决定
//本类为多态前提条件的案例
#include <iostream>
using namespace std;
class TradesPerson
{ public:
virtual void sayHi()
{ cout<<"hi."<<endl; }
};
class Tinker : public TradesPerson
{ public:
virtual void sayHi()
{ cout<<"I tinker."<<endl; }
};
class Tailor : public TradesPerson
{ public:
virtual void sayHi()
{ cout<<"I tailor."<<endl; }
};
int main()
{ TradesPerson* p;
int which;
do {
cout<<"1 == TradesPerson, 2 == Tinker, 3 == Tailor";
cin>>which;
} while (which < 1 || which > 3);
switch (which)
{ case 1 : p = new TradesPerson; break;
case 2 : p = new Tinker; break;
case 3 : p = new Tailor; break;
}
p->sayHi(); //动态绑定
//此处用来实施对sayHi的调用
delete p;
return 0;
}
基类型的指针数组,用随机数决定生成那个对象!
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
class TradesPerson
{ public:
virtual void sayHi() {cout<<"Just hi."<<endl;}
};
class Tinker : public TradesPerson
{ public:
virtual void sayHi() {cout<<"Hi, I tinker."<<endl;}
};
class Tailor : public TradesPerson
{ public:
virtual void sayHi() {cout<<"Hi, I tailor."<<endl;}
};
int main() {
srand( (unsigned) time( NULL ) ); //Sets a random starting point.
TradesPerson* ptrs[10];
unsigned which , i ;
for (i=0; i<10; i++) {
which = 1 + rand() % 3;
switch (which) {
case 1 : ptrs[i] = new TradesPerson; break;
case 2 : ptrs[i] = new Tinker; break;
case 3 : ptrs[i] = new Tailor; break;
}
}
for (i=0; i<10; i++) {
ptrs[i] -> sayHi();
delete ptrs[ i ];
}
return 0;
}
当声明了基类的一个成员函数为虚函数的时候,即使该成员函数没有在派生类中被显示的声明为虚函数,但是它所在的派生类中也将自动成为虚函数。
如果虚函数在类声明之外定义的,关键字vitual仅仅在声明的时候需要,在定义的时候可以不写。
注意:C++仅仅允许将成员函数定义为虚函数,不能将顶层函数定义为虚函数。
virtual void f(); //error
int main(){
.......
}
以下是个例子
#include <iostream>
using namespace std;
class High
{ protected:
float H;
public:
High(float h)
{ H=h;}
virtual void Show() //在基类中定义虚函数Show()
{ cout<<"High="<<H<<endl;}
};
class Cuboid:public High
{ private:
float Length,Width;
public:
Cuboid(float l=0,float w=0,float h=0):High(h)
{ Length=l; Width=w;}
virtual void Show() //在长方体派生类中定义虚函数Show()
{ cout<<"Length="<<Length<<'\t';
cout<<"Width="<<Width<<'\t';
cout<<"High="<<H<<'\n';
cout<<"Cuboid Volume="<<Length*Width*H<<endl;
}
};
class Cylinder:public High
{ private:
float R;
public:
Cylinder(float r=0,float h=0):High(h)
{R=r;}
virtual void Show() //在圆柱体派生类中定义虚函数Show()
{ cout<<"Radius="<<R<<'\t';
cout<<"High="<<H<<'\n';
cout<<"Cylinder Volume="<<R*R*3.1415*H<<endl;
}
};
void main(void)
{ High h(10),*p;
Cuboid cu(10,10,10);
Cylinder cy(10,10);
h.Show();
cu.Show();
cy.Show();
p=&h;
p->Show();
p=&cu;
p->Show();
p=&cy;
p->Show();
}
虚函数也是可以继承的!!!
class A{
public:
virtual void sayHello(){cout<<"Hello"<<end1}
}
class B : public A{
}
int main(){
B b;
b.sayHello();
}
//结果输出Hello
构造函数不能是虚函数,但是析构函数可以是虚函数。
class A {
public:
virtual A();//Error
virtual A(int);//Error
virtual ~A();//Right
virtual void m();
}
原因在于虚拟调用是一种能在给定信息下不完全的情况下的工作机制。虚拟允许调用某个函数,对于这个函数,仅仅知道他的接口,而不知道具体的类型。但是要创建一个对象,必须要拥有完全的信息,需要知道建立的对象的具体类型。
虚析构函数确实很有必要的,看下这段代码
#include <iostream>
using namespace std;
class A {
public:
A() { cout<<endl<<"A() firing"<<endl; //*p = new char[5];
};
~A() { cout<<"~A() firing"<<endl; //delete [ ] p;
}
private:
char* p;
};
class Z : public A
{ public:
Z() {
cout<<"Z() firing"<<endl;
//q = new char[5000];
};
~Z() {
cout<<"~Z() firing"<<endl;
//delete [ ] q;
}
private:
char* q;
};
void f()
{ A* ptr;
ptr = new Z();
//delete ptr;
}
int main()
{ for (unsigned i = 0; i<3; i++) f();
return 0;
}
如果说析构函数不是虚成员函数的话,那么编译器实施静态绑定!!!
结果会造成内存泄漏!!!