1.基类的指针(请注意,指针的赋值是需要同类型地址的)
继承的好处是一个指向子类的指针与一个指向基类的指针是类型兼容的(type-compatible)
继承的好处是一个指向子类的指针与一个指向基类的指针是type-compatible的,如以下代码所示:
#include <iostream>
using namespace std;
class Cfather{
protected:
int wigth,height;
public:
void get_value(int,int);
};
class Ctriangle:public Cfather{
public:
int tri_area(void){return (wigth*height/2);}
};
class Crectangle:public Cfather{
public:
int rect_area(void){return wigth*height;}
};
void Cfather::get_value(int a,int b)
{
wigth=a;
height=b;
}
int main()
{
Ctriangle tri;
Crectangle rect;
Cfather *tri_x=&tri; //定义一个Cfather类型的指针,然后给这个指针进行赋值,前提是类型需要一致才可以这么操作。
Cfather *rect_x=▭//继承的好处就是指向子类的指针与指向基类的指针是同个类型的。
tri_x->get_value(2,3);//其实这个也相当于(*tri_x.get_value)
rect_x->get_value(3,4);
cout<<tri.tri_area()<<rect.rect_area()<<endl;
return 0;
}
在主函数中定义了俩个指向Cfather对象的指针,即*tri_x和*rect_x俩个指针,分别被赋予了俩个子类对象的地址。
但是俩点需要注意:
1.tri_x和rect_x必须是Cfather *类型的,因为Ctriangle和CRectangle是其子类,因此我们只能引用从基类继承而来的成员,只能使用wigth、height和get_value等成员。
2。申明的指针虽然赋予了子类的对象,但是*tri_x和*rect_x不能调用子类的函数成员和数据成员。
2.虚拟成员
如果想在基类中定义一个成员留在子类中进行细化,我们必须在前面加个关键字virtual,以便可以使用指针指向相应的对象进行操作。
#include <iostream>
using namespace std;
class Cfather{
protected:
int wigth,height;
public:
void get_value(int,int);
virtual int area(void){return 0;} //在这行代码中,用了关键字virtual,表明这个函数要留在子类中进行定义,同时也使得Cfather类型指针能够访问到这个函数
};
class Ctriangle:public Cfather{
public:
int area(void){return wigth*height;} //对函数virtual进行详细定义
};
class Crectangle:public Cfather{
public:
int area(void){return wigth*height;}
};
void Cfather::get_value(int a,int b)
{
wigth=a;
height=b;
}
int main()
{
Ctriangle tri;
Crectangle rect;
Cfather *tri_x=&tri; //申明一个Cfather类型的指针,将子类对象的地址赋值给他是没有错的。
Cfather *rect_x=▭//在这里要注意,需要调用哪个子类的函数,那么就必须用相应的地址给他。
(*tri_x).get_value(2,3);
rect_x->get_value(3,4);
cout<<tri_x->area()<<rect_x->area()<<endl; //现在就可以访问这个函数了
return 0;
}
//在上述代码中,如果没有了关键字virtual,那么程序执行就不再是调用相应的area()函数(Cfather::area(),CTriangle::area(),CRectangle::area()),而是直接全部调用基类中的这个area函数。
因此,关键字virtual的作用就是当使用基类的指针的时候,可以使得子类中与基类同名的成员在适当的时候被调用。
但是在这里要注意,需要调用哪个子类的函数,那么就必须用相应的地址给他。
3.抽象基类(abstract base classes)
基本的抽象类与我们前面例子中的类Cfather非常相似,唯一的区别是在我们前面的例子中,我们定义了一个有效的area()函数,即virtual int area(void){return 0;},而在抽象类中,可以不对它定义,而是简单的 virtual int area(void)=0;
lass Cfather{
protected:
int wigth,height;
public:
void get_value(int,int);
virtual int area(void) = 0;//这种函数叫做纯虚拟函数,含有纯虚拟函数的基类叫做抽象基类
};
抽象基类不能申明对象(实例):Cfather fat;非法的
但是申明指针是完全没有问题的:Cfather *fath;完全没有问题
因为该类包含的纯虚拟函数是没有被实现的,而又不能生成一个不包含它的所有成员定义的对象。但是这个函数在子类被完全定义了。
#include <iostream>
using namespace std;
class Cfather{
protected:
int wigth,height;
public:
void get_value(int,int);
virtual int area(void)=0;
void output(void)
{
cout<<this->area()<<endl; //this代表正在执行的对象的指针,当*tri_x指针指向Tritangle 的对象tri的时候,this就是这个tri的指针,说白了就是this是tri_x的别名
}
};
class Ctriangle:public Cfather{
public:
int area(void){return wigth*height;}
};
class Crectangle:public Cfather{
public:
int area(void){return wigth*height;}
};
void Cfather::get_value(int a,int b)
{
wigth=a;
height=b;
}
int main()
{
Ctriangle tri;
Crectangle rect;
Cfather *tri_x=&tri;
Cfather *rect_x=▭
(*tri_x).get_value(2,3);
rect_x->get_value(3,4);
tri_x->output();
rect_x->output();
return 0;
}