C++语言基础(9)-继承
一.继承的基本语法
#include<iostream> using namespace std; //基类 Pelple class People{ public: void setname(char *name); void setage(int age); char *getname(); int getage(); private: char *m_name; int m_age; }; void People::setname(char *name){ m_name = name; } void People::setage(int age){ m_age = age; } char* People::getname(){ return m_name; } int People::getage(){ return m_age;} //派生类 Student class Student: public People{ public: void setscore(float score); float getscore(); private: float m_score; }; void Student::setscore(float score){ m_score = score; } float Student::getscore(){ return m_score; } int main(){ Student stu; stu.setname("小明"); stu.setage(16); stu.setscore(95.5f); cout<<stu.getname()<<"的年龄是 "<<stu.getage()<<",成绩是 "<<stu.getscore()<<endl; return 0; }
继承的基本语法为:
class 派生类名:[继承方式] 基类名{
派生类新增加的成员
};
在本例中,class 后面的“Student”是新声明的子类,冒号后面的“People”是已经存在的基类。在“People”之前有一关键宇 public,用来表示是公有继承。继承方式包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 private。
二.继承权限和继承方式
public、protected、private 指定继承方式
不同的继承方式会影响基类成员在派生类中的访问权限。
1) public继承方式
- 基类中所有 public 成员在派生类中为 public 属性;
- 基类中所有 protected 成员在派生类中为 protected 属性;
- 基类中所有 private 成员在派生类中不能使用。
2) protected继承方式
- 基类中的所有 public 成员在派生类中为 protected 属性;
- 基类中的所有 protected 成员在派生类中为 protected 属性;
- 基类中的所有 private 成员在派生类中不能使用。
3) private继承方式
- 基类中的所有 public 成员在派生类中均为 private 属性;
- 基类中的所有 protected 成员在派生类中均为 private 属性;
- 基类中的所有 private 成员在派生类中不能使用。
例:
#include<iostream> using namespace std; //基类People class People{ public: void setname(char *name); void setage(int age); void sethobby(char *hobby); char *gethobby(); protected: char *m_name; int m_age; private: char *m_hobby; }; void People::setname(char *name){ m_name = name; } void People::setage(int age){ m_age = age; } void People::sethobby(char *hobby){ m_hobby = hobby; } char *People::gethobby(){ return m_hobby; } //派生类Student class Student: public People{ public: void setscore(float score); protected: float m_score; }; void Student::setscore(float score){ m_score = score; } //派生类Pupil class Pupil: public Student{ public: void setranking(int ranking); void display(); private: int m_ranking; }; void Pupil::setranking(int ranking){ m_ranking = ranking; } void Pupil::display(){ cout<<m_name<<"的年龄是"<<m_age<<",考试成绩为"<<m_score<<"分,班级排名第"<<m_ranking<<",TA喜欢"<<gethobby()<<"。"<<endl; } int main(){ Pupil pup; pup.setname("小明"); pup.setage(15); pup.setscore(92.5f); pup.setranking(4); pup.sethobby("乒乓球"); pup.display(); return 0; }
也可以使用using关键字来改变访问权限
#include<iostream> using namespace std; //基类People class People{ public: void show(); protected: char *m_name; int m_age; }; void People::show(){ cout<<m_name<<"的年龄是"<<m_age<<endl; } //派生类Student class Student: public People{ public: void learning(); public: using People::m_name; //将private改为public using People::m_age; //将private改为public float m_score; private: using People::show; //将public改为private }; void Student::learning(){ cout<<"我是"<<m_name<<",今年"<<m_age<<"岁,这次考了"<<m_score<<"分!"<<endl; } int main(){ Student stu; stu.m_name = "小明"; stu.m_age = 16; stu.m_score = 99.5f; stu.show(); //compile error stu.learning(); return 0; }
三.调用子类构造函数时必须先调用父类构造函数
和Java中子类的构造函数初始化相似,当需要对父类的私有成员变量进行初始化时,需要调用父类的构造函数。
例:
#include<iostream> using namespace std; //基类People class People{ protected: char *m_name; int m_age; public: People(char*, int); }; People::People(char *name, int age): m_name(name), m_age(age){} //派生类Student class Student: public People{ private: float m_score; public: Student(char *name, int age, float score); void display(); }; //People(name, age)就是调用基类的构造函数 Student::Student(char *name, int age, float score): People(name, age), m_score(score){ } void Student::display(){ cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl; } int main(){ Student stu("小明", 16, 90.5); stu.display(); return 0; }
运行结果:
小明的年龄是16,成绩是90.5。
若不显示指明父类的构造函数,则默认调用父类的无参构造函数,例:
#include <iostream> using namespace std; //基类People class People{ public: People(); //基类默认构造函数 People(char *name, int age); protected: char *m_name; int m_age; }; People::People(): m_name("xxx"), m_age(0){ } People::People(char *name, int age): m_name(name), m_age(age){} //派生类Student class Student: public People{ public: Student(); Student(char*, int, float); public: void display(); private: float m_score; }; Student::Student(): m_score(0.0){ } //派生类默认构造函数 Student::Student(char *name, int age, float score): People(name, age), m_score(score){ } void Student::display(){ cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl; } int main(){ Student stu1; stu1.display(); Student stu2("小明", 16, 90.5); stu2.display(); return 0; }
运行结果:
xxx的年龄是0,成绩是0。
小明的年龄是16,成绩是90.5。
注意:如果将People类中的无参构造函数删除,则会发生编译错误!因为Student类的第一个构造函数没有显示的声明父类的构造函数,因此编译器就会寻找父类的无参构造函数,若发现父类没有无参构造函数,则会出现错误!
四.子类的析构函数会优先于父类的析构函数被调用
#include <iostream> using namespace std; class A{ public: A(){cout<<"A constructor"<<endl;} ~A(){cout<<"A destructor"<<endl;} }; class B: public A{ public: B(){cout<<"B constructor"<<endl;} ~B(){cout<<"B destructor"<<endl;} }; class C: public B{ public: C(){cout<<"C constructor"<<endl;} ~C(){cout<<"C destructor"<<endl;} }; int main(){ C test; return 0; }
运行结果:
多继承下的构造函数与析构函数
#include <iostream> using namespace std; //基类 class BaseA{ public: BaseA(int a, int b); ~BaseA(); protected: int m_a; int m_b; }; BaseA::BaseA(int a, int b): m_a(a), m_b(b){ cout<<"BaseA constructor"<<endl; } BaseA::~BaseA(){ cout<<"BaseA destructor"<<endl; } //基类 class BaseB{ public: BaseB(int c, int d); ~BaseB(); protected: int m_c; int m_d; }; BaseB::BaseB(int c, int d): m_c(c), m_d(d){ cout<<"BaseB constructor"<<endl; } BaseB::~BaseB(){ cout<<"BaseB destructor"<<endl; } //派生类 class Derived: public BaseA, public BaseB{ public: Derived(int a, int b, int c, int d, int e); ~Derived(); public: void show(); private: int m_e; }; Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){ cout<<"Derived constructor"<<endl; } Derived::~Derived(){ cout<<"Derived destructor"<<endl; } void Derived::show(){ cout<<m_a<<", "<<m_b<<", "<<m_c<<", "<<m_d<<", "<<m_e<<endl; } int main(){ Derived obj(1, 2, 3, 4, 5); obj.show(); return 0; }
运行结果:
BaseA constructor
BaseB constructor
Derived constructor
1, 2, 3, 4, 5
Derived destructor
BaseB destructor
BaseA destructor
五.当多个父类中有同名的成员时,子类在调用时,需要在成员名字前加::
当两个或多个基类中有同名的成员时,如果直接访问该成员,就会产生命名冲突,编译器不知道使用哪个基类的成员。这个时候需要在成员名字前面加上类名和域解析符::
,以显式地指明到底使用哪个类的成员,消除二义性。
例:
#include <iostream> using namespace std; //基类 class BaseA{ public: BaseA(int a, int b); ~BaseA(); public: void show(); protected: int m_a; int m_b; }; BaseA::BaseA(int a, int b): m_a(a), m_b(b){ cout<<"BaseA constructor"<<endl; } BaseA::~BaseA(){ cout<<"BaseA destructor"<<endl; } void BaseA::show(){ cout<<"m_a = "<<m_a<<endl; cout<<"m_b = "<<m_b<<endl; } //基类 class BaseB{ public: BaseB(int c, int d); ~BaseB(); void show(); protected: int m_c; int m_d; }; BaseB::BaseB(int c, int d): m_c(c), m_d(d){ cout<<"BaseB constructor"<<endl; } BaseB::~BaseB(){ cout<<"BaseB destructor"<<endl; } void BaseB::show(){ cout<<"m_c = "<<m_c<<endl; cout<<"m_d = "<<m_d<<endl; } //派生类 class Derived: public BaseA, public BaseB{ public: Derived(int a, int b, int c, int d, int e); ~Derived(); public: void display(); private: int m_e; }; Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){ cout<<"Derived constructor"<<endl; } Derived::~Derived(){ cout<<"Derived destructor"<<endl; } void Derived::display(){ BaseA::show(); //调用BaseA类的show()函数 BaseB::show(); //调用BaseB类的show()函数 cout<<"m_e = "<<m_e<<endl; } int main(){ Derived obj(1, 2, 3, 4, 5); obj.display(); return 0; }
运行结果:
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库