⭐上篇模板文章:24. C++模板 2 (非类型模板参数,模板的特化与模板的分离编译)-CSDN博客
⭐本篇代码:c++学习 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)
⭐标⭐是比较重要的部分
目录
一. 继承的基础使用
1.1 继承的格式
1.2 代码举例
1.3 派生类访问基类成员的变化⭐
二. 继承的复制兼容规则 ⭐
三. 继承中的作用域
3.1 基类可以访问父类成员函数
3.2 基类与派生类的重定义
一. 继承的基础使用
继承的面向对象程序设计提高代码复用的重要手段,它允许我们在保持原有类的成员的基础上对这个类进行拓展。之前我们大多都是函数的复用,继承是类的复用。
被继承的类称为基类(父类),继承基类的类称为派生类(子类)。
比如我们有一个person类,而学生,职工,教师等类都有着person类的属性(年龄,性别,电话,身份证等)而学生有自己特有的学号,教师职工有自己的工号。
此时我们就能通过继承让学生,教师,职工类获取person的成员,还能重新定义自己特有的成员。
1.1 继承的格式
class Person
{};class Student :public Person
{};
在新定义的类后面使用一个 : 后面依次接 继承方式 基类
1.2 代码举例
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "张三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年龄:" << _age << endl;}
private:size_t _age;string _name;
};class Student :public Person
{
private:string _stuid;
};class Teacher :public Person
{
private:string _tcid;
};int main()
{Person p1;p1.print();Student st1;st1.print();Teacher tc1;tc1.print();return 0;
}
上面代码中我们定义一个person类,在定义学生和教师类来继承person 。
我们都调用print函数,运行结果如下:
可见:学生类和教师类(派生类)都能够继承person类(基类)的姓名,年龄和print函数
1.3 派生类访问基类成员的变化⭐
继承的方式有三种,public,protected,private。不同的继承方式,子类访问父类有限定。
类成员/继承方式 | public继承 | protected继承 | private继承 |
基类public成员 | 派生类public成员 | 派生类protected成员 | 派生类private成员 |
基类protected成员 | 派生类protected成员 | 派生类protected成员 | 派生类private成员 |
基类private成员 | 派生类不可访问 | 派生类不可访问 | 派生类不可访问 |
根据上述表格,我们可以有以下总结
1 基类的private成员在派生类中不可见。即这个成员被派生类继承,但是在派生类的类内类外都无法访问基类的private成员
2 protected继承就是为了解决基类private成员无法在派生类访问的问题(即如果我们想要在派生类访问基类的私有成员,在基类中将其定义为protected成员即可)
3 实际上,为了提高代码的复用和拓展。我们一般都使用public继承
4 class定义类的默认继承方式是private,struct定义类的默认继承方式是public。不过我们在使用中一般都会显示定义类的继承方式。
若是保护成员,在派生类中可以访问
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "张三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年龄:" << _age << endl;}
protected:size_t _age;string _name;
};class Student :public Person
{
public:void show(){cout << "姓名:" << _name << " 年龄:" << _age << endl;}
private:string _stuid;
};int main()
{Person p1;p1.print();Student st1;st1.show();return 0;
}
我们在Student类中定义一个show函数来访问基类的保护成员
二. 继承的复制兼容规则 ⭐
派生类的对象可以赋值给 基类,基类的指针,基类的引用(称为切片,切割)
基类的对象不能赋值给派生类
基类的指针在特定情况下可以强制转化为派生类的指针
代码举例:
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "张三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年龄:" << _age << endl;}
protected:size_t _age;string _name;
};class Student :public Person
{
public:void set(int age, const string& name,int stuid){_age = age;_name = name;_stuid = stuid;}void show(){cout << "姓名:" << _name << " 年龄:" << _age << " ID:" << _stuid << endl;}
private:string _stuid;
};int main()
{Student st1;st1.set(50, "李四", 123456);st1.print();Student st2;Person p1 = st1; //直接赋值p1.print();Person* p2 = &st2; //基类指针p2->print();Person& p3 = st2; //基类引用p3.print();return 0;
}
运行结果如下:
若是将基类赋值给派生类就会报错
三. 继承中的作用域
1 在继承中,基类和派生类有自己独立的作用域。对于派生类来说,调用成员的时候会现在自己的类中寻找,如果自己的类中没有定义,再去基类中寻找成员
2 基类和其派生类有相同名称的成员,派生类会隐藏基类的成员。这两个成员构成重定义。
3 重定义不是重载。虽然两个成员名称相同,但是它两的作用域不一样,不是重载
3.1 基类可以访问父类成员函数
举例代码如下:基类没有print函数,会去父类寻找并调用print函数
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "张三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年龄:" << _age << endl;}
protected:size_t _age;string _name;
};class Student :public Person
{
private:string _stuid;
};int main()
{Student st1;st1.print();return 0;
}
测试结果如下:
3.2 基类与派生类的重定义
如果父子类有重定义,子类无法直接调用父类的成员
调用自己的成员
#include <iostream>
using namespace std;class A
{
public:void f() { cout << "hello world!" << endl; }
};class B :public A
{
public:void f(int i) { cout << "hello world!" << i << endl; }
};int main()
{A a;B b;a.f();b.f(10);return 0;
}
如果父子类构成重定义,子类想要访问父类同名成员,需要指定作用域