在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度。现在将跟着视频做的笔记进行整理。本篇博客是整理C++知识点的第十五篇博客。
本篇博客介绍了C++的继承。
本系列博客所有C++代码都在Visual Studio 2022环境下编译运行。程序为64位。
目录
继承
继承的基本语法
有些时候,类之间具有一定的关系。一些类拥有其他类的共性,和自己的特性。
可以利用继承,减少重复的代码。继承的语法是:
class A: 继承方式 B
继承方式分为public protected和private
A类称为子类,或派生类。B类称为父类,或基类。
子类的成员既有父类的成员,也有自己的成员。从父类继承的成员体现了共性,子类自己的成员体现了个性。
#include<iostream>
using namespace std;
class same {
public:
void show(void) {
cout << "It is object oriented programming" << endl;
}
void test(void) {
cout << "Study this is very hard" << endl;
}
void thing(void) {
cout << "It has encapsulation,inheritance and polymorphism" << endl;
}
};
class Java :public same
{
public:
void inform(void) {
cout << "This is Java" << endl;
}
};
class CPP :public same
{
public:
void inform(void) {
cout << "This is C++" << endl;
}
};
int main(void)
{
Java learnjava;
learnjava.inform();
learnjava.show();
learnjava.test();
learnjava.thing();
CPP learncpp;
learncpp.inform();
learncpp.show();
learncpp.test();
learncpp.thing();
return 0;
}
same类有三个成员函数,show成员函数输出It is object oriented programming,test成员函数输出Study this is very hard,thing成员函数输出It has encapsulation,inheritance and polymorphism。Java类以public权限继承了same类,该类自己的成员函数inform输出This is Java。CPP类以public权限继承了same类,该类自己的成员函数inform输出This is C++。
main函数定义了Java类对象learnjava和C++类对象learncpp,分别调用其成员函数,可见子类可以有父类的成员。程序的输出是:
This is Java
It is object oriented programming
Study this is very hard
It has encapsulation,inheritance and polymorphism
This is C++
It is object oriented programming
Study this is very hard
It has encapsulation,inheritance and polymorphism
继承方式
如果类A以public的继承方式继承了类X,那么X的public权限成员在A中仍然为public,X的protected权限成员在A中仍然为protected,X的private权限成员在A中不可访问。
如果类B以protected的继承方式继承了类X,那么X的public权限成员和protected权限成员在A中均为protected,X的private权限成员在A中不可访问。
如果类C以private的继承方式继承了类X,那么X的public权限成员和protected权限成员在A中均为private,X的private权限在A中不可访问。
#include<iostream>
using namespace std;
class base {
public:
int A;
protected:
int B;
private:
int C;
};
class son1 :public base
{
public:
void func(void) {
A = 10;
B = 10;
}
void show(void) {
cout << "A = " << A << endl;
cout << "B = " << B << endl;
}
};
class son2 :protected base
{
public:
void func(void) {
A = 12;
B = 12;
}
void show(void) {
cout << "A = " << A << endl;
cout << "B = " << B << endl;
}
};
class son3 :private base
{
public:
void func(void) {
A = 11;
B = 11;
}
void show(void) {
cout << "A = " << A << endl;
cout << "B = " << B << endl;
}
};
int main(void)
{
son1 s1;
s1.func();
s1.A = 15;
s1.show();
son2 s2;
s2.func();
s2.show();
son3 s3;
s3.func();
s3.show();
return 0;
}
base类的成员变量A B C分别为public protected private。子类son1 son2 son3分别以public protected private的方式继承了base类,并且都有func成员函数进行赋值,show成员函数用于输出。main函数中创建了son1 son2 son3类的对象并调用func函数show函数。
程序的输出是:
A = 15
B = 10
A = 12
B = 12
A = 11
B = 11
继承中的对象模型
父类的所有非静态成员属性都会被子类继承,即使子类无法访问,也是被继承了。
#include<iostream>
using namespace std;
class base {
public:
int A;
protected:
int B;
private:
int C;
};
class son :public base
{
public:
int D;
void func(void) {
A = 5;
B = 10;
D = 0;
}
};
int main(void)
{
son s;
cout << sizeof(s) << endl;
return 0;
}
base类有public权限的成员属性A,protected权限的成员属性B,private权限的成员属性C,共三个成员属性。类son以public继承了base,自身还有成员属性D和成员函数func。
main函数创建了son类对象s,并输出其大小。程序的输出是:16
即使son类不可访问C,但是依然继承了C。
继承中的构造和析构顺序
创建子类对象也会调用父类的构造函数。先构造父类再构造子类,析构相反。
#include<iostream>
using namespace std;
class father {
public:
father() {
cout << "A" << endl;
}
~father() {
cout << "Z" << endl;
}
};
class son :public father
{
public:
son() {
cout << "a" << endl;
}
~son() {
cout << "z" << endl;
}
};
int main(void)
{
son s;
return 0;
}
father类的构造函数输出A,析构函数输出Z。father类的子类son的构造函数输出a,析构函数输出z。main函数创建了一个son类的对象s。程序的输出是:
A
a
z
Z
继承的同名成员处理
当子类与父类的成员属性同名时,通过子类对象,访问子类的同名成员直接访问即可,访问父类的同名成员则需要加作用域。
如果子类出现和父类同名的成员函数,则子类的成员函数隐藏父类的同名成员函数,访问父类的同名函数需要加作用域。
#include<iostream>
using namespace std;
class father {
public:
void func() {
cout << "This is father's func" << endl;
}
void func(int num) {
cout << "This is father's func" << endl;
cout << "And there is a number = " << num << endl;
}
int number = 5;
};
class son :public father
{
public:
int number = 10;
void func() {
cout << "This is son's func" << endl;
}
};
int main(void)
{
son s;
cout << "Son's number is " << s.number << endl;
cout << "Father's number is " << s.father::number << endl;
s.func();
s.father::func();
s.father::func(100);
return 0;
}
father类有成员变量number,起始值为5,此外重载了两个func成员函数,一个没有参数,输出This is father's func,另一个接收一个int类型变量,并会输出其值。son类以public的权限继承了father类,内有成员变量number,起始值为10,还有成员函数func输出This is son's func。这样父类和子类出现了成员属性同名和成员变量同名。
main函数创建了son类对象s,并访问其本身和父类的同名成员函数以及同名成员变量。
程序的输出是:
Son's number is 10
Father's number is 5
This is son's func
This is father's func
This is father's func
And there is a number = 100
如果继承时出现了同名静态成员,那么通过子类对象,依然是访问子类的直接访问,访问父类的需要加作用域。
#include<iostream>
using namespace std;
class father {
public:
static int number;
static void func(void) {
cout << "This is father's func" << endl;
}
};
class son :public father
{
public:
static int number;
static void func(void) {
cout << "This is son's func" << endl;
}
};
int father::number = 10;
int son::number = 15;
int main(void)
{
cout << "son's number = " << son::number << endl;
cout << "father's number = " << son::father::number << endl;
son s;
cout << "son's number = " << s.number << endl;
cout << "father's number = " << s.father::number << endl;
s.func();
s.father::func();
son::func();
son::father::func();
return 0;
}
父类father和子类son都有静态成员变量number(都类外赋值),和静态成员函数func(输出不同语句)。main函数通过子类类名和子类对象访问了同名静态成员。程序的输出是:
son's number = 15
father's number = 10
son's number = 15
father's number = 10
This is son's func
This is father's func
This is son's func
This is father's func
多继承
C++允许一个类继承多个类,语法是:
class 子类:继承方式 父类1 继承方式 父类2...{...}
多继承可能导致父类中出现同名成员,需要用作用域区分。实际开发不建议使用多继承。
#include<iostream>
using namespace std;
class father1
{
public:
int A;
int C;
};
class father2
{
public:
int B;
int C;
};
class son :public father1, public father2
{
public:
int D;
};
int main(void)
{
son s;
s.A = 10;
s.B = 20;
s.father1::C = 15;
s.father2::C = 16;
s.D = 12;
cout << "A in father1 is " << s.A << endl;
cout << "B in father2 is " << s.B << endl;
cout << "C in father1 is " << s.father1::C << endl;
cout << "C in father2 is " << s.father2::C << endl;
cout << "D in son is " << s.D << endl;
return 0;
}
类father1有成员变量A和C,类father2有成员变量B和C,类son同时继承father1和father2,自身还有成员变量D。main函数创建了son类对象s,并访问其成员。由于son的两个父类都有成员变量C,因此需要用作用域区分。程序的输出是:
A in father1 is 10
B in father2 is 20
C in father1 is 15
C in father2 is 16
D in son is 12
如果类B和类C都继承自类A,而类D同时继承类B和类C。那么A的成员变量在B和C中可能有两个值,导致与事实的冲突。
virtual关键字表示虚继承,被虚继承的类是虚基类,这样数据只有一份。
#include<iostream>
using namespace std;
class first {
public:
int number;
};
class second1 : virtual public first {
};
class second2 :virtual public first {
};
class third : public second1, public second2 {
};
int main(void)
{
third three;
three.second1::number = 20;
cout << three.second1::number << endl;
cout << three.number << endl;
three.second2::number = 25;
cout << three.second2::number << endl;
cout << three.number << endl;
return 0;
}
first类有成员变量number,second1和second2对first类进行虚继承,而third类同时继承second1和second2。
main函数创建了third的类对象three,并通过两个不同父类作用域修改number为不同值,这时运行结果:
20
20
25
25
虚继承保证了这种继承的在子类数据的唯一性。