1.当继承方式是public时,才会讨论多态。
1)派生类的对象给基类的对象赋值
Drived d;
Base b;
b = d;
Base* p = new Base;
*p = d;
delete p;
2)一个派生类可以当作基类引用来用
- 派生类的对象初始化一个基类的引用
-
派生类的对象作为函数的形参(基类的引用)
-
派生类的对象作为函数的值返回,函数的返回值是一个基类的引用
派生类的对象有两部分:一部分是基类的,另一部分是派生类。当派生类的对象作为一个基类的引用来使用的时候。这个派生类的对象就好像是一个基类的对象。换句话说,就是这个派生类的对象只能访问基类的部分而不能访问派生类的部分。
值得注意的是,如果一个函数在基类里声明,在派生类里重写。派生类的对象作为基类的引用来调用这个函数,那么将调用基类版本的函数
派生类的对象作为基类对象的引用,作为函数的形参或作为函数的返回值。都会保留派生类对象的属性,尽管它看上去像个基类的对象。
Base& fun( Base& b ) { Derived* p= new Derived; return *p; } Derived d; Base& b = fun(d); delete &b;
3)基类的指针指向派生类的对象
- 基类的指针可以指向派生类的对象
- 一个指向派生类的指针可以赋值给一个基类的指针
- 派生类的指针可以当做基类的指针来作函数的形参
- 派生类的指针可以当做基类的指针来返回
Derived d;
Base* b = &d;
Base* fun( Base* b )
{
Derived* p= new Derived;
return p;
}
Derived d;
Base* b = fun(&d);
delete b;
4)
派生类的指针可以引用为一个基类指针的引用。这种情况发生在,当一个派生类的指针以引用的形式传给函数,函数接受的类型是一个基类的指针的引用。在这种情况下,这个派生类的指针在这个函数里当作基类的指针来使用
。
Base* fun( Base*& b )
{
Derived* p= new Derived;
return p;
}
Derived* p1 = &d;
fun(p1);
下面写一个例子来演示一下:
class Point
{
friend ostream & operator<<(ostream &,Point &);
public:
Point(double xval=0,double yval=0)
{
x=xval;
y=yval;
}
void print()
{
cout<<"Point:X:Y "<<x<<","<<y<<"\n";
}
protected:
double x;
double y;
};
ostream & operator<<(ostream &os,Point &apoint)
{
os<<"Point:X:Y "<<apoint.x<<","<<apoint.y<<"\n";
return os;
}
class Circle:public Point
{
friend ostream & operator<<(ostream &,Circle&);
public:
Circle(double r=0,double xval=0,double yval=0):Point(xval,yval)
{
radius=r;
}
void print()
{
cout<<"Circle:radius:"<<radius<<endl;
cout<<" Point:X:Y "<<x<<","<<y<<"\n";
}
double area()
{
return (3.1415926*radius*radius);
}
protected:
double radius;
};
ostream & operator<<(ostream & os,Circle & aCircle)
{
os<<"Circle:radius:"<<aCircle.radius;
os<<(Point&)aCircle<<"\n";
return os;
}
int main(int argc, char *argv[])
{
Point p(2,3);
cout<<"Point p="<<p<<endl;
Point pp(0,0);
cout<<"Point pp="<<pp<<endl;
Circle c(7,6,5);
cout<<"Circle c="<<c<<endl;
pp=p;
cout<<"Point pp="<<pp<<endl;
pp=c;
cout<<"Point pp="<<pp<<endl;
pp=(Point)c;
cout<<"Point pp="<<pp<<endl;
//c=(Circle)pp;
Point* pPoint;
pPoint = &c;
pPoint ->print();
((Circle*) pPoint)->print();
Point& r = c;
r.print();
((Circle&)r).print();
cout<<"Hello C-Free!"<<endl;
return 0;
}
注意:
在这些情况下,通过这个指针,派生类的对象好像一个基类的对象。指针可以是基类的指针,也可以是基类的指针引用了派生类的指针。然而,这个对象并没有改变,始终是一个派生类的对象
另一方面,一个基类的对象不能当成一个派生类的对象来使用。值得注意的是,如果一个基类的对象给一个派生类的对象赋值是错误的或者是把一个基类的指针赋给一个派生类的指针,或者传一个基类的对象或引用,当作一个派生类来用
然而,如果一个基类的指针指向一个派生类的对象,它可以被显示的转换为指向派生类的指针。从而可以调用派生的成员函数。这种转换叫做向下转换。但是,向下转换在程序当中是有风险的,因为基类的指针不一定能确切的指向派生类的对象。标准c++提供了安全的转换方法。
在这两种情况下,函数的形参的行为都是基类的行为,但是它们却又着很大的区别。我们可以声明一些函数,这些函数叫虚函数。有基类的版本和派生类的版本。靠虚函数来区分对象的真实身份,而不是引用或指针。
虚函数下章讲解。