继承就是在一个已存在的类的基础上建立一个新的类。
已存在的类称为基类,又称父类;新建立类称为派生类,又称为子类。
继承允许我们依据另一个类来定义一个类,不需要重新编写一部分的数据成员和成员函数,达到了重用代码功能和提高执行效率的效果。
基类与派生类
一个类可以派生自多个类,从多个基类继承数据和函数。我们使用一个类派生列表来指定基类。
class derived-class: access-specifier base-class
其中,访问修饰符 access-specifier
是 public
、protected
或 private
其中的一个,如果未指定则默认 private
。
搬运一个例子
class Shape {
public:
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
class Rectangle: public Shape {
public:
int getArea() {
return (width * height);
}
};
int main(void) {
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
cout << "Total area: " << Rect.getArea() << endl;
}
派生类继承了基类的属性,继承了基类的行为,可以添加额外的行为,也可以重新定义这些行为。
若基类定义的数据成员和派生类添加的数据成员同名,基类数据成员被覆盖。注意,即使函数名相同,参数不同,也无法调用基类函数。
在访问时,句柄的类型决定哪个类的成员被访问。使用对象名或引用访问同名成员,根据引用的类型决定,使用基类指针访问同名的成员,根据指针类型决定。
访问控制
派生类可以访问基类中所有的非私有成员。一个派生类继承了除去构造函数、析构函数、重载运算符、友元函数以外所有的基类方法.
不同继承类型的规则如下
- 公有继承(public):
- 基类的公有成员也是派生类的公有成员
- 基类的保护成员也是派生类的保护成员
- 基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
- 保护继承(protected):
- 基类的公有和保护成员将成为派生类的保护成员。
- 私有继承(private):
- 基类的公有和保护成员将成为派生类的私有成员。
基类的友元函数可以访问基类中的私有成员,以及派生类从基类中继承的成员。派生类中的友元函数只能访问派生类的私有成员,而不能访问基类中的私有成员。
拷贝构造函数仅用于同类拷贝或派生类向基类拷贝,而不能用于基类向派生类拷贝。
虚拟与多态
虚函数与纯虚函数
定义虚函数是为了允许用基类的指针来调用子类的这个函数。
例如以下程序的输出结果为 B
class A {
public:
virtual void foo() {
cout<<"A"<<endl;
}
};
class B:public A {
public:
void foo() {
cout<<"B"<<endl;
}
};
int main() {
A *a = new B();
a->foo();
}
在这里,调用的是哪个函数不是在编译时刻被确定的,而是在运行时刻被确定的。换言之,在编译时,并不知道被调用的是基类的函数还是哪个派生类的函数。
定义一个函数为纯虚函数,代表函数没有被实现,只是为了实现一个接口。它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。定义方式为
virtual void func()=0;
多态
在面向对象语言中,接口的多种不同的实现方式即为多态。
类的多态允许将子类类型的指针赋值给父类类型的指针。赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。
从应用的角度说,在基类的函数前加上 virtual
关键字声明为虚函数后,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
所有虚类的对象里面会自动加上一个隐藏指针,指向一张属于类的表 vtable,里是所有 virtual 函数的地址。
带有虚函数的类
每一个类都有虚表,且虚表可以继承。
如果子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。
如果重写了相应的虚函数,那么虚表中的地址就会改变,指向自身的虚函数实现。
如果派生类有自己的虚函数,那么虚表中就会添加该项。
所谓类的多态性,即将基类的函数定义为虚函数,在派生类中重写,运行时将会根据对象的实际类型来调用相应的函数。
注意区分类的多态性与函数的多态性。函数的多态性指一个函数被定义成多个不同参数的函数,调用这个函数时,就会调用不同的同名函数。
总结
派生类继承自基础类,可以描述基类对象集合中一组更细化、特殊的对象。派生类继承了基类的属性,继承了基类的行为,可以添加额外的行为,也可以重新定义这些行为。
虚函数是为了允许用基类的指针来调用子类的这个函数。调用的是哪个函数不是在编译时刻被确定的,而是在运行时刻被确定的。
定义一个函数为纯虚函数,代表函数没有被实现,只是为了实现一个接口。它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。
类的多态允许将子类类型的指针赋值给父类类型的指针。赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。