C++ 继承(1): 继承方式(public, protected, private), 继承中的特殊关系(隐藏 , is-a)

本文是C++远征之继承篇视频教程的笔记。介绍了C++类继承,包括其概念、作用,还阐述了继承方式,如公有、保护和私有继承。同时讲解了继承中的特殊关系,如隐藏和is - a关系,以及多继承、多重继承和虚继承等内容,并给出了相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++远征之继承篇 视频教程 笔记 方便自己查阅和复习,温故而知新。

 

目录

1 c++ 继承简介

代码示例

2 继承方式

总结

3 继承中的特殊关系

3.1 隐藏

代码示例

3.2 is-a

代码示例

4 多继承与多重继承

5 虚继承

参考资料


 

1 c++ 继承简介

通常,类库是以源代码的方式提供的,这意味着可以对其进行修改,以满足要求。然而,C++提供了比修改代码更好的方法来拓展和修改类,这种方法称之为 类继承,它能够从已有的类派生出新的类,而派生类继承原有类的特征,包括方法。 例如继承一笔财产要比自己白手起家容易,通过继承派生出的类通常比设计新的类容易得多。

但是生活中的继承 和 C++中的继承不能等同。

 

那么为什么要继承呢? 下面举一个例子,比较这两种类,Worker类用到了Person类的数据成员以及成员函数,如果不去重新定义,而是直接拿来用,那将会很方便。

 

所以 我们可以 在Worker中 将Person继承过来,形式如下:

 

下面介绍一下类继承所用到的专有名词:

 

那么在内存中,子类父类 的关系 如下图所示:

 

 

代码示例

要求:查看 父类 和子类构造函数 执行地先后顺序

1 定义Person类,要求含有m_strNmae 和 m_iAge两个数据成员及构造函数 析构函数 eat函数

2 定义Worker类,要求共有继承Person类,含有数据成员m_iSalary , 构造函数 析构函数 work函数

 

//Person.h
#pragma once
#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person();//构造函数
	~Person();//析构函数

	void eat();
	string m_strName;
	int m_iAge;

};
//Person.cpp

#include<iostream>
#include"Person.h"
using namespace std;


Person::Person()
{
	cout << "Person() 构造" << endl;
}

Person::~Person()
{
	cout << "~Person() 析构" << endl;
}

void Person::eat()
{
	cout << "Person eat()" << endl;
}


//Worker.h

#pragma once
#include<iostream>
#include"Person.h"

using namespace std;

class Worker:public Person//公有继承
{
public:
	Worker();
	~Worker();

	void work();
	int m_iSalary;
};
//Worker.cpp

#include<iostream>
#include"Worker.h"
using namespace std;

Worker::Worker()
{
	cout << "Worker() 构造" << endl;
}

Worker::~Worker()
{
	cout << "~Worker() 析构" << endl;
}

void Worker::work()
{
	cout << "Worker work()" << endl;
}
//main.cpp

#include<iostream>
#include"Worker.h"
using namespace std;
/*************************
类继承
要求:查看 父类 和子类 构造函数 执行地先后顺序
1 定义Person类,要求含有m_strNmae 和 m_iAge两个数据成员 及 构造函数 析构函数 eat函数
2 定义Worker类,要求共有继承Person类,含有数据成员m_iSalary , 构造函数 析构函数 work函数

**************************/


int main()
{
	Worker *p = new Worker;
	p->m_strName = "SB";
	p->m_iAge = 3;
	p->eat();

	cout << "-------------------" << endl;
	p->m_iSalary = 10000;
	p->work();

	delete p;
	p = NULL;

	cin.get();
	return 0;
}

运行结果:

 

:由实验结果可知:

构造函数: 先执行父类的构造函数 后执行子类的构造函数;

析构函数:先执行子类的析构函数 后执行父类的析构函数。

 

 

2 继承方式

类继承 有三种方式:

 

例如,公有继承 如下:

 

公有继承的访问:

 

那么 对于 protected 只能继承 不能访问,如下图所示:

 

 

总结

public 继承:

 

protected 继承:

 

private 继承:

 

 

3 继承中的特殊关系

3.1 隐藏

继承中的特殊关系,子类的数据成员或成员函数 与 父类的数据成员或成员函数 同名,此时,父类的称之为:隐藏

 

这种隐藏 可以 概括为: 父子关系 成员同名 隐藏

那么 如何访问 子类和父类的 同名函数呢? 下面举一个例子来说明:

 

 

对于 子类和父类的 数据成员同名 也同样举一个例子,如下图所示:

 

 

 

代码示例

继承关系中的 隐藏
要求:
1 定义Person类
    数据成员: m_strName 
    成员函数:构造函数, play()

2 定义Soldier类:
    数据成员: 无
    成员函数:构造函数, play() worker()

 

//Person.h
#pragma once
#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person();//构造函数
	~Person();//析构函数


	void play();
	string m_strName;
	int m_iAge;

};
//Person.cpp

#include<iostream>
#include"Person.h"
using namespace std;


Person::Person()
{
	cout << "Person() 构造" << endl;
}

Person::~Person()
{
	cout << "~Person()--析构" << endl;
}

void Person::play()
{
	cout << "Person--play()" << endl;
}

 

//Soldier.h

#pragma once
#include<iostream>
#include"Person.h"

class Soldier:public Person
{
public:
	Soldier();
	void play();//与父类中的函数同名
	void work();

protected:
};
//Soldier.cpp

#include<iostream>
#include"Soldier.h"
using namespace std;
Soldier::Soldier()
{
	cout << "Soldier() 构造" << endl;
}

void Soldier::play()
{
	cout << "Soldier---play()" << endl;
}

void Soldier::work()
{
	cout << "Soldier---work()" << endl;
}

 

//main.cpp

#include<iostream>
#include"Soldier.h"
using namespace std;
/*************************
继承关系中的 隐藏
要求:
1 定义Person类
	数据成员: m_strName 
	成员函数:构造函数, play()

2 定义Soldier类:
	数据成员: 无
	成员函数:构造函数, play() worker()
**************************/


int main()
{
	Soldier soldier;
	soldier.play();
	cout << "-------------------" << endl;
	soldier.Person::play();
	soldier.work();
	

	cin.get();
	return 0;
}

运行结果:

 

 

3.2 is-a

如下图所示, 工人和人是一种 is-a 关系, 士兵和人同样也是 is-a 关系。但工人和士兵不是 is-a 关系

 

 

 

下面从内存角度 来说明 is-a 的关系:

 

 

代码示例

示例1:

要求:继承关系中的 is-a
1 定义Person类
    数据成员: m_strName 
    成员函数:构造函数  析构函数 play()

2 定义Soldier类:
    数据成员: m_iAge
    成员函数:构造函数  析构函数  worker()

//Person.h
#pragma once
#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person(string name="pesrson_001");//构造函数
	~Person();//析构函数

	void play();

protected:
	string m_strName;

};
//Person.cpp

#include<iostream>
#include"Person.h"
using namespace std;


Person::Person(string name)
{
	m_strName = name;
	cout << "Person()--构造" << endl;
}

Person::~Person()
{
	cout << "~Person()--析构" << endl;
}

void Person::play()
{
	cout << "Name: " << m_strName << endl;
	cout << "Person--play()" << endl;
}

 

//Soldier.h

#pragma once
#include<iostream>
#include"Person.h"

class Soldier:public Person
{
public:
	Soldier(string name = "soldier_001", int age = 20);
	~Soldier();
	void work();

protected:
	int m_iAge;
};
//Soldier.cpp

#include<iostream>
#include"Soldier.h"
using namespace std;
Soldier::Soldier(string name, int age)
{
	m_strName = name;
	m_iAge = age;
	cout << "Soldier()--构造" << endl;
}

Soldier::~Soldier()
{
	cout << "~Soldier--析构" << endl;
}

void Soldier::work()
{
	cout << "Name= "<< m_strName << endl;
	cout << "Age= " << m_iAge << endl;
	cout << "Soldier--work()" << endl;
}

 

//main.cpp

#include<iostream>
#include"Soldier.h"
using namespace std;
/*************************
继承关系中的 is-a
要求:
1 定义Person类
	数据成员: m_strName 
	成员函数:构造函数  析构函数 play()

2 定义Soldier类:
	数据成员: m_iAge
	成员函数:构造函数  析构函数  worker()

**************************/


int main()
{
	Soldier soldier1;
	Person person1 ;
	soldier1.play();
	person1.play();

	cout << "" << endl;
	cout << "---------- 1 -----------" << endl;
	cout << "" << endl;

	Soldier soldier2;
	Person person2 = soldier2;//soldier2初始化person2
	person2.play(); //此时 person2中的m_strName被 soldier2初始化时更改了
	//因为 m_strName是继承下来的 所以可以通过子类对父类继承下来的成员进行赋值 


	cout << "" << endl;
	cout << "---------- 2 -----------" << endl;
	cout << "" << endl;


	//使用指针 对继承父类的成员进行赋值
	Soldier soldier3;
	Person *p1 = &soldier3;
	p1->play();//与上面的效果一样,对父类的成员进行赋值了
	

	cout << "" << endl;
	cout << "---------- 3 -----------" << endl;
	cout << "" << endl;


	//看 释放内存 执行 哪一个析构函数
	Person *p2 = new Soldier;//父类指针 指向子类
	p2->play();
	delete p2;
	p2 = NULL;//只执行 父类的析构函数 可能造成内存泄漏 这时 需要用 虚函数(在父类和子类前加入 virtual)

	cin.get();
	return 0;
}

运行结果:

 

总结:

由结果可以知道:

(1) 子类可以赋值给父类,只能赋值继承下来的成员;

(2) 父类指针指向子类时,只能指向子类继承下来的成员;

(3) 在父类指针 指向 子类时,释放内存 只执行了父类的析构函数,这可能会造成内存泄漏 这时 需要用 虚析构函数 (在父类和子类的虚构函数前加入 virtual 关键字)  即可。

 

 

示例2:

继承关系中的 is-a 函数传递 
要求:
1 定义Person类
    数据成员: m_strName 
    成员函数:构造函数  析构函数 play()

2 定义Soldier类:
    数据成员: m_iAge
    成员函数:构造函数  析构函数  worker()

3 定义函数test1(Person p) test2(person &p) test3(Person *p)

这里只有main.cpp不同 其他函数文件均与示例1相同。

//main.cpp

#include<iostream>
#include"Soldier.h"
using namespace std;
/*************************
继承关系中的 is-a
要求:
1 定义Person类
	数据成员: m_strName 
	成员函数:构造函数  析构函数 play()

2 定义Soldier类:
	数据成员: m_iAge
	成员函数:构造函数  析构函数  worker()

3 定义函数test1(Person p) test2(person &p) test3(Person *p)
**************************/
void test1(Person p)
{
	p.play();
}

void test2(Person &p)
{
	p.play();
}

void test3(Person *p)
{
	p->play();
}



int main()
{
	Person p;
	Soldier s;
	cout << "" << endl;
	cout << "---------- 1 -----------" << endl;

	test1(p);//接受值时 临时实例化  通过临时对象 调用函数play 结束后 对象自动销毁(调用析构函数)
	cout << "------------------------" << endl;
	test1(s);

	cout << "" << endl;
	cout << "---------- 2 -----------" << endl;
	cout << "" << endl;


	test2(p);//没有产生新的临时对象
	cout << "------------------------" << endl;
	test2(s);

	cout << "" << endl;
	cout << "---------- 3 -----------" << endl;
	cout << "" << endl;


	test3(&p); //没有产生新的临时对象
	cout << "------------------------" << endl;
	test3(&s);

	cin.get();
	return 0;
}

运行结果:

注:由实验结果可知,test1(). test2()和test3() 三个函数调用时,调用test1()函数,会产生新的临时对象,而test2() 和test3()函数不会,所以test2() 和test3()函数的效率更高。

 

4 多继承与多重继承

 

5 虚继承

由于视频教程知识点较多,所以分开记录,便于查找和复习。详见:C++ 继承(2): 多重继承, 多继承, 虚继承(virtual)

 

 

参考资料

[1] C++远征之继承篇  (注:图片均来自视频中PPT)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechArtisan6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值