1、继承
[1].语法:
class Shape{
//父类
}
class Rectangle: public Shape{
//子类
}
[2].多继承;基类之间用逗号隔开。
class Rectangle: public Shape, public PaintCost{
代码块
};
2、多态(难点)
当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
举例:基类 Shape 被派生为两个类
class Shape {
int width, height; //定义了两个变量
int area() { //定义了求面积函数
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape{
public:
int area (){}//求矩形面积的函数实现
}
class Triangle: public Shape{
public:
int area (){}//求三角形面积的函数实现
}
// 程序的主函数
int main() {
Shape *shape;
Rectangle rec(10,7); //实例化一个矩形对象
Triangle tri(10,5); //实例化一个三角形对象
shape = &rec; // 存储矩形的地址
area shape->area();// 调用矩形的求面积函数
shape = &tri; // 存储三角形的地址
area shape->area();// 调用三角形的求面积函数
return 0;
}
每个子类都有一个函数 area() 的独立实现。这就是多态的一般使用方式。有了多态,多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。
3、虚函数
[1].虚函数的概念:
首先:强调一个概念
定义一个函数为虚函数,不代表函数为不被实现的函数。
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
定义一个函数为纯虚函数,才代表函数没有被实现。
定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
class A{
public:
virtual void foo(){
cout<<"A::foo() is called"<<endl;
}
};
class B:public A{
public:
void foo(){
cout<<"B::foo() is called"<<endl;
}
};
int main(void){
A *a = new B();
a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
return 0;
}
动态链接:我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,把这种操作称为动态链接。这也是所谓的“虚”。
搞了半天,其实就是把子类实例化对象赋值给父类类型的变量。而所谓的“虚函数”,就是父类中被定义的一些子类可以调用的函数。这与继承有什么区别呢?
虚函数只能借助于指针或者引用来达到多态的效果。
[2].虚函数的语法:
虚函数的是由两个部分组成的,虚函数指针与虚函数表。
虚函数指针:虚函数指针 (virtual function pointer) 从本质上来说就只是一个指向函数的指针,与普通的指针并无区别。它指向用户所定义的虚函数,具体是在子类里的实现,当子类调用虚函数的时候,实际上是通过调用该虚函数指针从而找到接口。
虚函数表:每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中都放着该虚函数表的指针(可以认为这是由编译器自动添加到构造函数中的指令完成的)。一个类的虚函数表中列出了该类的全部虚函数地址。
#include <iostream>
using namespace std;
class A{
public:
int i;
virtual void func() {}
virtual void func2() {}
};
class B : public A{
int j;
void func() {}
};
int main(){
cout << sizeof(A) << ", " << sizeof(B); //输出 8,12
return 0;
}
在 32 位编译模式下,程序的运行结果是:8, 12
如果将程序中的 virtual 关键字去掉,输出结果变为:4, 8
对比发现,有了虚函数以后,对象所占用的存储空间比没有虚函数时多了 4 个字节。实际上,任何有虚函数的类及其派生类的对象都包含这多出来的 4 个字节,这 4 个字节就是实现多态的关键——它位于对象存储空间的最前端,其中存放的是虚函数表的地址。
4、纯虚函数:
[1].定义
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
virtual void funtion1()=0
[2].纯虚函数的意义
让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。
注:纯虚函数,就是java、php语言中的抽象函数。拥有抽象函数的类称为抽象类,c++中拥有纯虚函数的类称为抽象类。
[3].纯虚函数的特点:
a.编译器要求必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化)
b.含有纯虚拟函数的类称为抽象类,它不能生成对象
c.C++中的纯虚函数也是一种“运行时多态”。
定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。
[4].纯虚函数语法:
虚函数的定义形式:virtual {method body}
纯虚函数的定义形式:virtual { } = 0;
#include <iostream>
#include <vector>
using namespace std;
class reslut{
public:
reslut(){}
int get_a(){
return a;
}
int get_b(){
return b;
}
void set_a(int x){
this->a = x;
}
void set_b(int y)
{
this->b = y;
}
~reslut()
{
}
virtual int test() = 0;
protected:
int a;
int b;
};
class AA : public reslut
{
public:
int test() //重写父类的纯虚函数
{
return a + b;
}
};
class BB :public reslut
{
public:
int test() //重写父类的纯虚函数
{
return a*b;
}
};
int main()
{
AA test1;
test1.set_a(1);
test1.set_b(2);
int reslut1= test1.test();
BB test2;
test2.set_a(1);
test2.set_b(2);
int reslut2 = test2.test();
return 0;
}