17.面向对象-继承-继承的基本规则
17.1 知识点
基本概念
一个类 A 继承一个类 B
类 A 将会继承类 B 的成员(不包括构造函数、析构函数和友元等)
A 类将拥有 B 类的特征和行为(根据访问权限决定能否访问)
被继承的类称为父类、基类、超类
继承的类称为子类、派生类
子类可以有自己的特征和行为
特点:
- 传递性:子类可以间接继承父类的父类(前提是访问权限允许)
- 多继承:子类可以有多个父类
基本语法
使用访问修饰符来改变父类成员在子类中的访问方式
语法格式:
class 子类名 : 继承方式 父类名 { // 子类自己的成员 };
访问修饰符回顾(3P):
- public —— 公共的,自己(内部)和别人(外部)都能访问和使用(完全公开)
- private —— 私有的,自己(内部)才能访问和使用,不写默认为 private(严格私有)
- protected —— 保护的,自己(内部)和子类才能访问和使用(对子类开放)
父类成员在不同继承方式下的访问级别:
父类原来级别 public 继承后 protected 继承后 private 继承后 public public protected 不可访问 protected protected protected 不可访问 private 不可访问 不可访问 不可访问 当前继承时不受影响,父类是什么样子就是什么样访问级别;若后续再继承,则会受到这里的限制。
实例
#pragma once
#include <iostream>
using namespace std;
class Teacher
{
public:
// 老师的名字
string name;
// 老师自我介绍的方法
void SpeakName()
{
number = 1;
f = 1.1f;
cout << name << endl;
}
protected:
int number = 0;
private:
float f = 2.3f;
};
#pragma once
#include "Teacher.h"
class TeachingTeacher : public Teacher
{
public:
string subject;
void SpeakSubject()
{
SpeakName();
// public 外部、内部、子类都能用
cout << name << endl; //(子类中使用)
// protected 内部、子类可以使用
cout << number << endl; //(子类中使用)
// private 内部使用
// cout << f << endl; //(子类中使用) // 报错
cout << subject << endl;
}
int x = 1;
void test()
{
cout << "TeachingTeacher" << endl;
}
void test2()
{
cout << "TeachingTeacher2" << endl;
}
};
#pragma once
#include "TeachingTeacher.h"
class ChineseTeacher : public TeachingTeacher
{
public:
void Skill()
{
// cout << number << endl;
cout << "一行白鹭上青天" << endl;
}
int x = 2;
using TeachingTeacher::test2;
void test()
{
cout << "ChineseTeacher" << endl;
}
void test2(int i)
{
cout << "ChineseTeacher2" << endl;
}
};
ChineseTeacher ct;
ct.name = "小韬老师";
ct.subject = "语文";
ct.SpeakName(); // 小韬老师
ct.SpeakSubject(); // 小韬老师\n小韬老师\n1\n语文
ct.Skill(); // 一行白鹭上青天
子类和父类的同名成员
C++ 中允许子类存在和父类同名的成员,但不建议这样使用
子类同名成员会覆盖父类成员
cout << ct.x << endl; // 2 打印 ChineseTeacher 的 x 变量 ct.test(); // ChineseTeacher
可通过作用域解析符
::
强制访问父类成员cout << ct.TeachingTeacher::x << endl; // 1 打印 TeachingTeacher 的 x 变量 ct.TeachingTeacher::test(); // TeachingTeacher //如果在内部用 直接 父类名::成员 //如果在外部用 直接 对象.父类名::成员
子类同名不同参数的成员函数会隐藏父类所有同名函数(即使参数不同也不能直接访问),可用
using 父类名::方法名;
解决隐藏问题//子类同名不同参数成员函数会隐藏父类成员 //当子类定义了一个和父类同名但参数不同的函数 //父类中所有同名函数都会被隐藏,即使参数不同也不能再直接访问! //可以通过 using 父类名::父类方法名 来解决隐藏问题 // //比如现在TeachingTeacher有个无参的test2方法 //ChineseTeacher有个有一个int参数的test2方法 //看起来是两个函数 //但是直接执行test2会报错 因为子类同名不同参数成员函数会隐藏父类成员 //ct.test2();//报错 //但是如果在ChineseTeacher类中 添加如下代码 //using TeachingTeacher::test2; //就可以正常执行 ct.test2();//TeachingTeacher2 ct.test2(666);//ChineseTeacher2
强行禁止类被继承
如果不希望一个类可以被继承,可使用
final
关键字修饰类语法:
class 类名 final { };
总结
继承的基本语法
class 子类名 : 继承方式 父类名 { // 子类自己的成员 };
父类成员在不同继承方式下的访问权限一览:
父类原来级别 public 继承后 protected 继承后 private 继承后 public public protected 不可访问 protected protected protected 不可访问 private 不可访问 不可访问 不可访问 继承方式使用访问修饰符来限制父类成员在后续继承中的可见性
特性:
- 传递性:子类可间接继承父类的父类
- 多继承:子类可有多个父类
17.2 知识点代码
Teacher.h
#pragma once
#include<iostream>
using namespace std;
class Teacher
{
public:
//老师的名字
string name;
//老师自我介绍的方法
void SpeakName()
{
number = 1;
f = 1.1f;
cout << name << endl;
}
protected:
int number = 0;
private:
float f = 2.3f;
};
TeachingTeacher.h
#pragma once
#include "Teacher.h"
class TeachingTeacher : public Teacher
{
public:
string subject;
void SpeakSubject()
{
SpeakName();
//public 外部 内部 子类都能用
cout << name << endl;//(子类中使用)
//protected 内部 子类可以使用
cout << number << endl;//(子类中使用)
//private 内部使用
//cout << f << endl;//(子类中使用)//报错
cout << subject << endl;
}
int x = 1;
void test()
{
cout << "TeachingTeacher" << endl;
}
void test2()
{
cout << "TeachingTeacher2" << endl;
}
};
ChineseTeacher.h
#pragma once
#include "TeachingTeacher.h"
class ChineseTeacher : public TeachingTeacher
{
public:
void Skill()
{
//cout << number << endl;
cout << "一行白鹭上青天" << endl;
}
int x = 2;
using TeachingTeacher::test2;
void test()
{
cout << "ChineseTeacher" << endl;
}
void test2(int i)
{
cout << "ChineseTeacher2" << endl;
}
};
Lesson17_面向对象_继承_继承的基本规则.cpp
#include <iostream>
using namespace std;
#include "ChineseTeacher.h"
int main()
{
#pragma region 知识点一 基本概念
//一个类A继承一个类B
//类A将会继承类B的成员(不包括构造函数、析构函数和友元等)
//A类将拥有B类的特征和行为(根据访问权限决定能否访问)
//被继承的类
//称为 父类、基类、超类
//继承的类
//称为子类、派生类
//子类可以有自己的特征和行为
//特点
//1.传递性 子类可以间接继承父类的父类(前提是访问权限允许)
//2.多继承 子类可以有多个父类
#pragma endregion
#pragma region 知识点二 基本语法
//class 子类名 : 继承方式 父类名
//{
// //子类自己的成员
//};
//继承方式就是使用访问修饰符来
//改变父类成员在子类中的访问方式
//
//回顾访问修饰符作用
// 3P
// public —— 公共的 自己(内部)和别人(外部)都能访问和使用(完全公开,任何地方都能访问)
// private —— 私有的 自己(内部)才能访问和使用 不写 默认为private(严格私有,只有当前类内部才能访问)
// protected —— 保护的 自己(内部)和子类才能访问和使用(对自己和子类开放,外部不可访问)
// 决定类内部的成员 的 访问权限
//
//父类成员原本访问级别 public继承后 protected继承后 private继承后
// public public protected 不可访问
// protected protected protected 不可访问
// private 不可访问 不可访问 不可访问
//继承方式 是用3P去限制父类中成员的访问级别的
//当前继承时,不会受到影响,父类是什么样就是什么样的访问级别
//但是如果之后还存在继承关系,那么之后的类就会收到这里的影响了
#pragma endregion
#pragma region 知识点三 实例
ChineseTeacher ct;
ct.name = "小韬老师";
ct.subject = "语文";
ct.SpeakName();//小韬老师
ct.SpeakSubject();
//小韬老师
//小韬老师
//1
//语文
ct.Skill();
//一行白鹭上青天
#pragma endregion
#pragma region 知识点四 子类和父类的同名成员
//C++中允许子类存在和父类同名的成员
//但是不建议这样使用
//子类同名成员会覆盖父类成员
cout << ct.x << endl;//2 打印的ChineseTeacher的x变量
ct.test();//ChineseTeacher
//但可以通过作用域解析符::来强制访问父类成员
//比如: 父类名::成员
cout << ct.TeachingTeacher::x << endl;//1 打印的TeachingTeacher的x变量
ct.TeachingTeacher::test();//TeachingTeacher
//如果在内部用 直接 父类名::成员
//如果在外部用 直接 对象.父类名::成员
//子类同名不同参数成员函数会隐藏父类成员
//当子类定义了一个和父类同名但参数不同的函数
//父类中所有同名函数都会被隐藏,即使参数不同也不能再直接访问!
//可以通过 using 父类名::父类方法名 来解决隐藏问题
//
//比如现在TeachingTeacher有个无参的test2方法
//ChineseTeacher有个有一个int参数的test2方法
//看起来是两个函数
//但是直接执行test2会报错 因为子类同名不同参数成员函数会隐藏父类成员
//ct.test2();//报错
//但是如果在ChineseTeacher类中 添加如下代码
//using TeachingTeacher::test2;
//就可以正常执行
ct.test2();//TeachingTeacher2
ct.test2(666);//ChineseTeacher2
#pragma endregion
#pragma region 知识点五 强行禁止类被继承
//如果我们不希望一个类可以被继承
//我们可以通过final关键词来修饰类
//基本语法:
//class 类名 final
//{
//}
//在类名后加上final关键字,就可以禁止该类被继承了
#pragma endregion
//总结
//继承的基本语法
//class 子类名 : 继承方式 父类名
//{
// //子类自己的成员
//};
//父类成员原本访问级别 public继承后 protected继承后 private继承后
// public public protected 不可访问
// protected protected protected 不可访问
// private 不可访问 不可访问 不可访问
//继承方式 是用3P去限制父类中成员的访问级别的
//当前继承时,不会受到影响,父类是什么样就是什么样的访问级别
//但是如果之后还存在继承关系,那么之后的类就会收到这里的影响了
//1.传递性 子类可以间接继承父类的父类(前提是访问权限允许)
//2.多继承 子类可以有多个父类
}
17.3 练习题
写一个人类,人类中有姓名,年龄属性,有说话行为,战士类继承人类,有攻击行为
#pragma once
#include <iostream>
using namespace std;
class Person
{
public:
string name;
int age;
void Speak(string str);
};
#include "Person.h"
void Person::Speak(string str)
{
cout << str << endl;
}
#pragma once
#include "Person.h"
class Warrior : public Person
{
public:
void Atk(Warrior& otherWarrior);
};
#include "Warrior.h"
void Warrior::Atk(Warrior& otherWarrior)
{
cout << this->name << "打了" << otherWarrior.name << endl;
}
Warrior w1;
w1.name = "韬老师";
w1.age = 18;
Warrior w2;
w2.name = "奥特曼";
w2.age = 999;
w1.Speak("我要打死你");
w1.Atk(w2);
w2.Speak("你相信光吗?");
w2.Atk(w1);
// 我要打死你
// 韬老师打了奥特曼
// 你相信光吗?
// 奥特曼打了韬老师
17.4 练习题代码
Person.h
#pragma once
#include <iostream>
using namespace std;
class Person
{
public:
string name;
int age;
void Speak(string str);
};
Person.cpp
#include "Person.h"
void Person::Speak(string str)
{
cout << str << endl;
}
Warrior.h
#pragma once
#include "Person.h"
class Warrior : public Person
{
public:
void Atk(Warrior& otherWarrior);
};
Warrior.cpp
#include "Warrior.h"
void Warrior::Atk(Warrior& otherWarrior)
{
cout << this->name << "打了" << otherWarrior.name << endl;
}
Lesson17_练习题.cpp
#include <iostream>
#include "Warrior.h"
int main()
{
#pragma region 练习题
/*写一个人类,人类中有姓名,年龄属性,有说话行为
战士类继承人类,有攻击行为*/
Warrior w1;
w1.name = "韬老师";
w1.age = 18;
Warrior w2;
w2.name = "奥特曼";
w2.age = 999;
w1.Speak("我要打死你");
w1.Atk(w2);
w2.Speak("你相信光吗?");
w2.Atk(w1);
//我要打死你
//韬老师打了奥特曼
//你相信光吗?
//奥特曼打了韬老师
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com