一:继承中的指针问题。(基类指针指向派生类对象)
1. 指向基类的指针可以指向派生类对象,当基类指针指向派生类对象时,这种指针只能访问派生对象从基类继承而来的那些成员,不能访问子类特有的元素,除非应用强类型转换,例如有基类B和从B派生的子类D,则B *p;D dd; p=&dd是可以的,指针p只能访问从基类派生而来的成员,不能访问派生类D特有的成员.因为基类不知道派生类中的这些成员。
2. 不能使派生类指针指向基类对象.
3. 如果派生类中覆盖了基类中的成员变量或函数,则当声明一个基类指针指向派生类对象时,这个基类指针只能访问基类中的成员变量或函数。例如:基类B和派生类D都定义了函数f,则B *p; D m; p=&m; ()将调用基类中的函数f()而不会调用派生类中的函数f()。4. 如果基类指针指向派生类对象,则当对其进行增减运算时,它将指向它所认为的基类的下一个对象,而不会指向派生类的下一个对象,因此,应该认为对这种指针进行的增减操作是无效的.
5.上面讲解了基类指针指向其派生类对象的用法,下面的代码将阐述为什么要使用基类指针指向其派生类对象:它可以实现多态性。即向不同的对象发送同一个消息,不同的对象在接受时会产生不同的行为。C++支持两种形式的多态性。第一种是编译时的多态性,称为静态联编。第二种是运行时的多态性,也称为动态联编。运行时的多态性是指必须在运行中才可以确定的多态性,是通过继承和虚函数来实现的。继承同一基类的不同派生对象,对来自基类的同一消息执行了不同的行为,这就是多态。
#include <iostream>
using namespace std;
class Shape {
public:
virtual double area() const = 0; //纯虚函数
};
class Square : public Shape {
double size;
public:
Square(double s) {
size = s;
}
virtual double area() const {
return size * size;
}
};
class Circle : public Shape {
double radius;
public:
Circle(double r) {
radius = r;
}
virtual double area() const {
return 3.14159 * radius * radius;
}
};
int main()
{
Shape* array[2]; //定义基类指针数组
Square Sq(2.0);
Circle Cir(1.0);
array[0] = &Sq;
array[1] =&Cir;
for (int i = 0; i < 2; i++)
{
cout << array[i]->area() << endl;
}
return 0;
}
二(补充):虚函数
1. 为什么要使用虚函数:正如上面第1和3点所讲的,当声明一个基类指针指向派生类对象时,这个基类指针只能访问基类中的成员函数,不能访问派生类中特有的成员变量或函数。如果使用虚函数就能使这个指向派生类对象的基类指针访问派生类中的成员函数,而不是基类中的成员函数,基于这一点派生类中的这个成员函数就必须和基类中的虚函数的形式完全相同,不然基类指针就找不到派生类中的这个成员函数。使用虚函数就实现了一个接口多种方法。
2. 注意不能把成员变量声明为虚有的,也就是说virtual关见字不能用在成员变量前面。
3. 正如上面所介绍的,一般应使用基类指针来调用虚函数,如果用点运算符来调用虚函数就失去了它的意义.
4. 如果基类含有虚函数则当声明了一个基类的指针时,当基类指针指向不同的派生类时,它就会调用相应派生类中定义的虚函数版本.这种调用方法是在运行时决定的,例如在类B中声明了虚函数,C,D,E都从B继承而来且都实现了自已的虚函数版本,那么当定义了一个B类的指针P时,当P指向子类C时就会调用子类C中定义的虚函数,当P指向子类D时就会调用子类D中定义的虚函数,当P指向子类E时就会调用子类E中定义的虚函数.
5. 虚函数须在基类中用virtual关键字声明,也可以在基类中定义并在一个或多个子类中重新定义.重定义虚函数时不需再使用virtual关键字,当然也可以继续标明virtual关键字,以便程序更好理解。
6. 包括虚函数的类被称为多态类.C++使用虚函数支持多态性.