【C++】从零开始认识继承
送给大家一句话:
其实我们每个人的生活都是一个世界,即使最平凡的人也要为他生活的那个世界而奋斗。 – 路遥 《平凡的世界》
✩◝(◍⌣̎◍)◜✩✩◝(◍⌣̎◍)◜✩✩◝(◍⌣̎◍)◜✩
✩◝(◍⌣̎◍)◜✩✩◝(◍⌣̎◍)◜✩✩◝(◍⌣̎◍)◜✩
✩◝(◍⌣̎◍)◜✩✩◝(◍⌣̎◍)◜✩✩◝(◍⌣̎◍)◜✩
从零开始认识继承
- 1 前言
- 2 什么是继承
- 3 开始使用继承
- 3.1 继承的语法格式
- 3.2 基类与派生类的赋值转换
- 3.3 继承中的作用域
- 3.4 派生类的默认成员函数
- 构造函数
- 拷贝构造函数
- 赋值构造函数
- 析构函数
- 总结
- 4 继承与友元
- 5 继承与静态变量
- 6 复杂的菱形继承及菱形虚拟继承
- 7 继承的总结和思考
- 8 有关继承的经典面试题
- Thanks♪(・ω・)ノ谢谢阅读!!!
- 下一篇文章见!!!
1 前言
在我们日常的编程中,继承的应用场景有很多。它可以帮助我们节省大量的时间和精力,避免重复造轮子的尴尬。同时,它也让我们的代码更加模块化,易于维护和扩展。可以说,继承技术是C++的灵魂。
那么,继承技术的起源又是什么呢?这得追溯到遥远的过去,当时的程序员们发现,许多类的属性和方法都是相似的,于是他们想出了一个绝妙的主意:为什么不把这些相似的部分提取出来,形成一个"父类",而其他的类则通过"继承"这个父类来获得这些属性和方法呢?这个想法,就是继承技术的雏形。
如今,继承技术已经成为C++编程中不可或缺的一部分。它让我们能够站在巨人的肩膀上,创造出更加高效、简洁的代码。当然,继承技术也不是万能的,它也有自己的局限性和注意事项。但是,这并不妨碍我们欣赏它的优雅,感受它带来的便利。
在这篇博客中,我将带你深入探讨C++继承技术的奥秘,让你能够更好地掌握这一强大的工具。准备好了吗?让我们一起踏上这场探索之旅,开启编程的新篇章 — C++进阶!!!
2 什么是继承
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
通过继承联系在一起的类构成一种层次关系,通常在层次关系的根部有一个基类(base class),其他类则是直接或间接地从基类继承过来的,这些继承来的类成为派生类(derived class)。基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类都有各自特定的成员。
举个例子:加入我们需要一个学校管理系统,那么成员包括学生,老师,保安,宿管…不管是什么身份,总得是个人吧,是人就会有名字,年龄,家庭住址等基础信息,那么我们就可以把这些共同的部分提炼出来作为基类。
#include using namespace std; //共同特性 class Person { public: void Print() { cout protected: int _stuid; // 学号 }; class Teacher : public Person { protected: int _jobid; // 工号 }; int main() { Student s; Teacher t; s.Print(); t.Print(); return 0; } public: Person(int age = 18, int sex = 1, int num = 0) :_age(age), _sex(sex), _num(num) {} void Print() { cout public: Student(int num = 0) :_num(num) { } void Print() { cout Student s(1111); s.Print(); return 0; } public: //因为不是全缺省函数没有默认构造 Person(const char* name ) : _name(name) { cout public: protected: int _num; //学号 }; void Test() { Student s1; } int main() { Test(); return 0; } public: Student(int num , const char* str ,const char* name) :_name(name), _num(num), _str(str) { } protected: int _num; //学号 string _str; }; public: Student(int num , const char* str ,const char* name) :Person(name), _num(num), _str(str) { } protected: int _num; //学号 string _str; }; public: BB(int num , const char* str ,const char* name) :_p(name), _num(num), _str(str) {} protected: Person _p int _num; //学号 string _str; }; public: Student(int num , const char* str ,const char* name) :Person(name), _num(num), _str(str) {} Student(const Student& s) :Person(s)//会进行切片,子类对象可以赋值给父类 -复用 ,_num(s._num) ,_str(s._str) {} protected: int _num; //学号 string _str; }; public: Student(int num , const char* str ,const char* name) :Person(name), _num(num), _str(str) {} Student& operator=(const Student& s) { //不能自己赋值自己 if(this != &s) { //注意标明作用域 , 否则会无限递归 Person::operator=(s); //进行切片来对父类进行赋值拷贝 -复用 _num = s._num; _str = s._str;//调用string的构造 } } protected: int _num; //学号 string _str; }; public: Student(int num , const char* str ,const char* name) :Person(name), _num(num), _str(str) {} ~Student(int num , const char* str ,const char* name) { ~Person(); cout public: Dad(int money = 100 , const char* house = "homeless") :_money(money) ,_house(house) {} friend void show(const Dad& d, const Son& s); protected: int _money; string _house; }; class Son : public Dad { public: Son(int homework = 100 ) :_homework(homework) {} //friend void show(const Dad& d, const Son& s); protected: int _homework;; }; void show(const Dad& d , const Son& s) { cout Dad d(10000, "翻斗花园"); Son s(12); show(d,s); return 0; } public: static int _a ; }; int A::_a = 1; class B : public A { public: protected: int b; }; int main() { B b1; B b2; B b3; cout public: Person() { ++_count; } protected: string _name; // 姓名 public: static int _count; // 统计人的个数。 }; int Person::_count = 0; class Student : public Person { protected: int _stuNum; // 学号 }; void TestPerson() { Student s1; Student s2; Student s3; cout TestPerson(); return 0; } public: string _name; // 大学名字 }; class uni211 : public university { protected: int _num; //编号 }; class uni985 : public university { protected: int _id; // 编号 }; class SDU : public uni211, public uni985 { protected: string _address; }; void Test() { // 这样会有二义性无法明确知道访问的是哪一个 SDU a; a._name = "peter"; // 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决 a.uni211::_name = "xxx"; a.uni985::_name = "yyy"; } public: string _name; // 大学名称 }; class uni211 : virtual public university { protected: int _num; //编号 }; class uni985 : virtual public university { protected: int _id; //编号 }; class SDU : public uni211, public uni985 { protected: string _address;//地址 }; void Test() { // 这样就只有一个_name了,不存在二义性的问题了 SDU a; a._name = "peter"; } public: int _a; }; class B : public A //class B : virtual public A { public: int _b; }; class C : public A //class C : virtual public A { public: int _c; }; class D : public B, public C { public: int _d; }; int main() { D d; d.B::_a = 1; d.C::_a = 2; d._b = 3; d._c = 4; d._d = 5; return 0; }

