【C++学习】对象特性--继承
一、继承的方式
基础语句
//类A继承类B,B为基类(父类),A为派生类(子类)
//class A:pulic B{};
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;
/*继承基本语句*/class BaseClass
{
public:void baseClassCout() { cout << "父类" << endl; };
};class SonClass1 : public BaseClass
{
public:void sonClassCout() { cout << "子类1" << endl; };
};void test1()
{SonClass1 son1;son1.baseClassCout();son1.sonClassCout();
};int main()
{system("chcp 65001 >nul"); // 汉化// using std::cout;test1();return 0;
}
继承方式
公共继承 public
保护继承 protected
私有继承 private
各继承方式的特点
使用public继承时,父类的public成员在子类中依旧为public成员,父类的protected成员在子类中为protected成员,按照此规律,继承特点如下表所示
注意:父类的 private成员 三种继承的子类都不能访问
公共继承 public 父 public->子 public 父 protected->子 protected
保护继承 protected 父 public->子 protected 父 protected->子 protected
私有继承 private 父 public->子 private 父 protected->子 private
二、父子实例的构造函数与析构函数执行顺序
父类构造函数->子类构造函数->子类析构函数->父类析构函数
class Parent {
public:Parent() { cout << "Parent 构造函数" << endl; }~Parent() { cout << "Parent 析构函数" << endl; } // 非虚析构(仅演示顺序)
};class Child : public Parent {
public:Child() { cout << "Child 构造函数" << endl; }~Child() { cout << "Child 析构函数" << endl; }
};int main() {Child c; // 创建子类对象,出作用域时自动销毁return 0;
}
三、父子实例同名成员访问方式
访问同名变量
#include <iostream>
using namespace std;class Parent {
public:int num = 10; // 父类成员变量
};class Child : public Parent {
public:int num = 20; // 子类同名成员变量(隐藏父类的num)
};int main() {Child c;cout << c.num << endl; // 直接访问:子类的num → 输出 20cout << c.Parent::num << endl; // 显式指定父类作用域:父类的num → 输出 10Child* ptr = &c;cout << ptr->num << endl; // 指针访问子类num → 20cout << ptr->Parent::num << endl; // 指针访问父类num → 10return 0;
}
访问同名函数
若父子类存在同名非虚函数(参数列表可不同),子类函数会隐藏父类所有同名函数(无论参数是否相同),直接调用时默认执行子类函数
class Parent {
public:void func() { cout << "Parent::func()" << endl; }void func(int x) { cout << "Parent::func(int) " << x << endl; } // 重载函数
};class Child : public Parent {
public:void func() { cout << "Child::func()" << endl; } // 隐藏父类所有func()
};int main() {Child c;c.func(); // 调用子类func() → 输出 Child::func()// c.func(10); // 编译报错!子类隐藏了父类的func(int),无法直接调用// 调用父类的func()和func(int)c.Parent::func(); // 输出 Parent::func()c.Parent::func(10); // 输出 Parent::func(int) 10return 0;
}
四、多继承语法
#include <iostream>
using namespace std;// 父类1:表示"能跑"的特性
class Runable {
public:void run() {cout << "可以奔跑" << endl;}
};// 父类2:表示"能飞"的特性
class Flyable {
public:void fly() {cout << "可以飞翔" << endl;}
};// 子类:同时继承 Runable 和 Flyable(如"飞毯"既可以跑也可以飞)
class Carpet : public Runable, public Flyable {
public:void display() {cout << "这是一个神奇的飞毯:" << endl;}
};int main() {Carpet c;c.display(); // 子类自身方法c.run(); // 继承自 Runable 的方法c.fly(); // 继承自 Flyable 的方法return 0;
}
五、菱形继承(钻石继承)
当多继承中出现 “两个父类继承自同一个基类” 的情况,会导致子类中存在间接基类的多份副本,引发数据冗余和访问歧义
问题演示
// 顶层基类
class Object {
public:int id;
};// 中间父类 A 和 B,都继承 Object
class A : public Object {};
class B : public Object {};// 子类 C 同时继承 A 和 B,导致 C 中包含两份 Object::id
class C : public A, public B {};int main() {C c;// c.id = 10; // 编译报错:歧义(A::id 还是 B::id?)c.A::id = 10; // 需显式指定,繁琐且不合理c.B::id = 20;return 0;
}
虚继承解决
通过在中间父类的继承方式前加 virtual 关键字,确保顶层基类在子类中只存在一份副本,避免冗余和歧义
class Object {
public:int id;
};// 中间父类用虚继承
class A : virtual public Object {}; // 虚继承 Object
class B : virtual public Object {}; // 虚继承 Object// 子类 C 继承 A 和 B,Object 仅一份副本
class C : public A, public B {};int main() {C c;c.id = 10; // 无歧义,直接访问唯一的 idreturn 0;
}
