1. C++多态公有继承概述
在面向对象的程序设计过程中,多态是一个非常重要的概念。多态通常通过继承来实现,C++中的多态特性可以通过公有继承来实现。公有继承是C++中继承类型中的一种,使用公有继承可以使派生类拥有基类的所有成员(除了构造和析构函数),并且可以在派生类中实现基类的虚函数来实现多态。
2. 多态的实现
2.1 虚函数
C++中的多态是通过虚函数来实现的。虚函数是一种在基类中声明的函数,它可以在派生类中被重载。当一个类包含虚函数时,编译器会在虚函数表中为该类生成一张虚函数表,虚函数表中存储了每个虚函数的地址,当调用虚函数时,会根据对象的类型来调用相应的虚函数。
class Base{
public:
virtual void func(){
cout << "Base::func()" << endl;
}
};
class Derived : public Base{
public:
void func(){
cout << "Derived::func()" << endl;
}
};
int main(){
Base *b = new Base();
Derived *d = new Derived();
b->func();
d->func();
delete b;
delete d;
return 0;
}
这段代码中,Base类中有一个虚函数func(),Derived类继承自Base类并重载了该虚函数。在程序中,创建了一个Base类和一个Derived类的对象,调用了它们的func()函数。由于Base类中的func()函数是虚函数,因此在调用b->func()时会调用到Base类中的func()函数,调用d->func()时会调用到Derived类中的func()函数。
2.2 多态的三个条件
实现多态需要满足下面三个条件:
存在继承关系:只有继承关系才能使基类指针指向派生类对象。
存在虚函数:虚函数是多态的前提条件,只有虚函数才能使编译器在运行时确定应该调用哪一个函数。
存在基类指针或引用:基类指针或引用可以指向派生类对象,这是多态的关键。
3. 公有继承的特点
3.1 访问权限
公有继承是C++中最常用的一种继承方式,它定义了一种“is-a”的关系,可以使派生类拥有基类的所有成员(除了构造和析构函数),并且可以在派生类中重新定义基类的虚函数以实现多态。
在公有继承中,从基类继承来的成员在派生类中的访问权限不变,即从基类中继承的public成员在派生类中仍为public,protect成员在派生类中仍为protected,而private成员在派生类中是不可见的。
class Base{
public:
int public_data;
void public_func(){
// ...
}
protected:
int protected_data;
void protected_func(){
// ...
}
private:
int private_data;
void private_func(){
// ...
}
};
class Derived : public Base{
public:
void func(){
public_data = 1; // 可以访问基类中的public成员
public_func(); // 可以调用基类中的public函数
protected_data = 1; // 可以访问基类中的protected成员
protected_func(); // 可以调用基类中的protected函数
// private_data = 1; // 不可访问基类中的private成员
// private_func(); // 不可调用基类中的private函数
}
};
3.2 构造函数和析构函数
在公有继承中,只要派生类对象被创建,就会先调用基类的构造函数再调用派生类的构造函数;当派生类对象要被销毁时,会先调用派生类的析构函数再调用基类的析构函数。
在基类和派生类中,构造函数和析构函数的调用顺序如下:
创建派生类对象时,先调用基类的构造函数再调用派生类的构造函数;
销毁派生类对象时,先调用派生类的析构函数再调用基类的析构函数。
class Base{
public:
Base(){
cout << "Base::Base()" << endl;
}
~Base(){
cout << "Base::~Base()" << endl;
}
};
class Derived : public Base{
public:
Derived(){
cout << "Derived::Derived()" << endl;
}
~Derived(){
cout << "Derived::~Derived()" << endl;
}
};
int main(){
Derived d; // 创建派生类对象
return 0;
}
运行结果如下:
Base::Base()
Derived::Derived()
Derived::~Derived()
Base::~Base()
在创建派生类对象时,先调用基类的构造函数再调用派生类的构造函数;当销毁派生类对象时,先调用派生类的析构函数再调用基类的析构函数。
4. 纯虚函数和抽象类
4.1 纯虚函数
在C++中,如果一个虚函数没有实现,就可以将其声明为纯虚函数。纯虚函数是在基类中声明的虚函数,在派生类中必须被实现。声明纯虚函数可以用“=0”来指定。
class Base{
public:
virtual void func() = 0; // 纯虚函数
};
class Derived : public Base{
public:
void func(){
cout << "Derived::func()" << endl;
}
};
在上面的代码中,Base类中的func()函数被声明为纯虚函数,Derived类中必须对其进行实现。在Derived类中实现了func()函数,并输出了一条信息。在程序中创建Derived类的对象,调用了它的func()函数。
int main(){
Base *d = new Derived();
d->func();
delete d;
return 0;
}
运行结果如下:
Derived::func()
4.2 抽象类
包含纯虚函数的类被称为抽象类,抽象类是无法被实例化的,只能作为基类被派生类继承。抽象类的派生类必须实现其基类中所有的纯虚函数,否则派生类也是抽象类。
抽象类一般用于表示一个概念性的基类或接口,其中定义了一些公有接口和属性,但对于如何实现这些接口和属性并没有提供具体的实现,需要在派生类中进行实现。
class Shape{
public:
virtual double area() const = 0; // 纯虚函数
};
class Rectangle : public Shape{
public:
Rectangle(double w, double h) : width(w), height(h){}
double area() const{
return width * height;
}
private:
double width;
double height;
};
class Circle : public Shape{
public:
Circle(double r) : radius(r){}
double area() const{
return 3.14 * radius * radius;
}
private:
double radius;
};
在上面的代码中,Shape是一个抽象类,它包含一个纯虚函数area()。Rectangle和Circle都是Shape的派生类,它们都实现了area()函数来计算各自的面积。在程序中,创建了一个Rectangle对象和一个Circle对象,调用它们的area()函数。
int main(){
Shape *rect = new Rectangle(3, 4);
Shape *cir = new Circle(2);
cout << "Rectangle area is " << rect->area() << endl;
cout << "Circle area is " << cir->area() << endl;
delete rect;
delete cir;
return 0;
}
运行结果如下:
Rectangle area is 12
Circle area is 12.56
5. 总结
公有继承是C++中最常用的一种继承方式,它可以使派生类拥有基类的所有成员(除了构造和析构函数),并且可以在派生类中重新定义基类的虚函数以实现多态。多态是C++面向对象编程中的一个重要概念,它能够在运行时实现不同类型的对象以不同的方式响应相同的函数调用。
在实现多态时,需要满足三个条件:存在继承关系、存在虚函数和存在基类指针或引用。公有继承满足这些条件,是实现多态的关键。
抽象类是包含纯虚函数的类,它是不能被实例化的,只能被用作基类被派生类继承。抽象类的派生类必须实现其基类中所有的纯虚函数,否则派生类也是抽象类。