一、什么是继承?
儿子从爸爸里面继承一些
资源过来。这样儿子就很快乐,儿子就不需要实现父亲的(功能)资源。
![](https://i-blog.csdnimg.cn/blog_migrate/6ab50497dc28d54e69f780b79c6cc7e9.png)
二、类的继承
继承
:
子类从父类中,继承数据成员和功能函数,继承后这些数据和函数可以在子类直接使用。
作用:
1.
提高代码的复用性,
2.
有利于软件版本的升级。
![](https://i-blog.csdnimg.cn/blog_migrate/9ebbc0f020d9f7a1b218e31d9e845be3.png)
提示:子类 与 父类 必须存在正常的逻辑关系,不要滥用继承。
1、继承的语法
class 类名 : 继承方式 父类名(基类名){//设计子类(派生类)的函数接口或成员}// 继承的 demo: 通过一个人派生出 警察// 设计基类(父类)class people{private :char name [ 100 ];int age ;};// 派生出 警察类 派生类 (子类)class police : public people{public :void CatchThief (){cout << " 警察抓住一个小偷啦 " << endl ;}}
#include <iostream>
using namespace std;
//设计基类(父类)
class people
{
private:
char name[100]; //姓名
int age; //年龄
char sex[100]; //性别
};
//派生出 警察类 派生类(子类)
class police : public people
{
public:
void CatchThief()
{
cout << "Police catch thief..." << endl;
}
};
int main()
{
police p;
p.CatchThief();
return 0;
}
编译运行结果如下所示:
练习1:定义一个动物类,包含 年龄和颜色,通过动物类,派生出 猫类 和 狗类,再设计它们特有的功能接口。
//定义一个动物类,包含 年龄和颜色,通过动物类,
//派生出 猫类 和 狗类,再设计它们特有的功能接口。
#include <iostream>
using namespace std;
//设计基类(父类)
class Animal
{
private:
int age; //年龄
char color[100]; //颜色
};
//派生出 猫类 派生类(子类)
class Cat : public Animal
{
public:
void CatchMice()
{
cout << "Cat catch mice..." << endl;
}
};
//派生出 狗类 派生类(子类)
class Dog : public Animal
{
public:
void GetFrisbe()
{
cout << "Dog get frisbe..." << endl;
}
};
int main()
{
Cat c;
c.CatchMice();
Dog d;
d.GetFrisbe();
return 0;
}
编译运行,结果如下:
2、继承的存储空间问题
#include <iostream>
using namespace std;
//设计基类(父类)
class base
{
private:
int date;
};
//设计一个派生类(子类)
class new_base : public base
{
private:
float f_date;
};
int main()
{
cout << "new_base size: " << sizeof(new_base) << endl;
return 0;
}
编译运行,结果如下所示:
可见,new_base 的空间大小是8,因为new_base是继承了base的,所以new_base里面还包含了base的空间大小。
分析继承的空间问题:
3、继承的权限问题(重点)
回顾类的属性权限class base{public : // 公共区 : 类内,类外,子类 都可以访问 (所有人都可以访问)protected : // 保护区 : 类内,子类 可以访问 , 类外不能访问private : // 私有区 : 类内可以访问。};
详解:
#include <iostream>
using namespace std;
//设计基类(父类)
class base
{
public:
int a;
//set_base 是 base的内部函数,所以属于类内访问,
//可以访问当前类的一切数据成员!!
void set_base()
{
a = 100;
b = 200;
c = 300;
}
protected:
int b;
private:
int c;
};
//设计一个派生类(子类)
class new_base : public base
{
public:
//new_base 是 base 的派生类(子类),子类可以访问
//父类的共用和保护成员
void set_newbase()
{
a = 400;
b = 500;
//c = 600; //不可以访问父类的私有成员
}
};
int main()
{
//定义一个 new_base 对象
new_base a;
//main函数 与 base 和 new_base 都没有任何关系,属于类外访问。
//类外只能访问共用成员
a.a = 100;
//a.b = 200; //不可以访问
//a.c = 300; //不可以访问
return 0;
}
那么,子类要如何去访问基类的私有成员?
答:在基类(保护区或共用区)中开发接口,提供子类访问。
#include <iostream>
using namespace std;
//设计基类(父类)
class base
{
protected:
//set_base 是 base的内部函数,所以属于类内访问,
//可以访问当前类的一切数据成员!!
void set_base(int a, int b)
{
this->a = a;
this->b = b;
}
void show_base()
{
cout << "a: " << a << endl;
cout << "b: " << b << endl;
}
private:
int a;
int b;
};
//设计一个派生类(子类)
//new_base 包含了两个数据成员,分配是int a,int b
class new_base : public base
{
public:
//设置数据
void set_data(int a, int b)
{
this->set_base(a,b);
}
//显示数据
void show_data()
{
this->show_base();
}
};
int main()
{
//定义一个 new_base 对象
new_base a;
a.set_data(100,200);
a.show_data();
return 0;
}
编译运行,结果如下所示:
练习2:设计一个角色类,包含私有成员, 力量,敏捷,智力,通过角色类派生出,法师类 和 战士类。定义派生类的对象,并调用派生类的接口,初始化角色类的数据成员,并输出。
#include <iostream>
using namespace std;
//设计基类(父类)
//角色类
class Role
{
protected:
void set_role(int force, int agility, int intelligence)
{
this->force = force;
this->agility = agility;
this->intelligence = intelligence;
}
//获取属性接口
int get_Force()
{
return force;
}
int get_Agility()
{
return agility;
}
int get_Intelligence()
{
return intelligence;
}
void show_role()
{
cout << "force: " << force << endl;
cout << "agility: " << agility << endl;
cout << "intelligence: " << intelligence << endl;
}
private:
int force; //力量
int agility; //敏捷
int intelligence; //智力
};
//设计派生类(子类)
//法师类
class Master : public Role
{
public:
//设置数据
void set_master(int force, int agility, int intelligence)
{
this->set_role(force,agility,intelligence);
}
//显示数据
void show_data()
{
this->show_role();
}
//攻击接口
void attack()
{
//冰冻攻击
cout << "Freezing attack: " << this->get_Force() << endl;
}
};
//战士类
class Soldier : public Role
{
public:
//设置数据
void set_soldier(int force, int agility, int intelligence)
{
this->set_role(force,agility,intelligence);
}
//显示数据
void show_data()
{
this->show_role();
}
//攻击接口
void attack()
{
//认真一拳
cout << "Give a serious punch: " << this->get_Force() << endl;
}
};
int main()
{
//定义一个 Master 对象
Master master;
master.set_master(50,78,120);
master.show_data();
master.attack();
//定义一个 Soldier 对象
Soldier soldier;
soldier.set_soldier(99,45,72);
soldier.show_data();
soldier.attack();
return 0;
}
编译运行,结果如下所示:
4、继承中的构造函数
在继承中所有构造函数都会执行, 先执行基类
构造,再执行派生类
构造。
#include <iostream>
using namespace std;
//设计基类(父类)
class base
{
public:
base(int a)
{
cout << "base(): " << a << endl;
}
base()
{
cout << "base()" << endl;
}
};
//设计一个派生类(子类)
class new_base : public base
{
public:
new_base()
{
//在创建 new_base 对象时,先调用 base 的构造函数,但是base的构造函数是一个有参数的。
//所以new_base无法调用得到。
//解决方法:
//1、添加一个无参的构造函数
//2、基类不写构造函数,使用系统自动生成的默认构造函数
cout << "new_base()" << endl;
}
};
int main()
{
//创建一个new_base对象
new_base a;
return 0;
}
编译运行,结果如下所示:
5、继承中的参数列表初始化
#include <iostream>
using namespace std;
//设计基类(父类)
class base
{
public:
base(int d) //base的构造
{
date = d;
}
int date;
};
//设计一个派生类(子类)
class new_base : public base
{
public:
new_base(int d,int d1):base(d1)
{
date = d;
}
int date;
};
int main()
{
//创建一个new_base对象
new_base tmp(100,200);
cout << tmp.date << endl;
cout << tmp.base::date << endl;
return 0;
}
编译运行,结果如下所示:
分析如下:
练习3:完成下来类的数据初始化,使用参数列表的方式
class base{public :int a ;char buf [ 1024 ];};class new_base : public base{public :short date ;float b ;};// 设计参数列表初始化,初始化 new_base 中的所有数据成员
#include <iostream>
#include <string.h>
using namespace std;
//设计基类(父类)
class base
{
public:
base(int a,const char *buf) //base的构造
{
this->a = a;
strcpy(this->buf,buf);
}
int a;
char buf[1024];
};
//设计一个派生类(子类)
//现在new_base中含有4个数据成员,两个自己的,两个继承过来的
//所以构造函数需要传递4个参数
class new_base : public base
{
public:
new_base(int a,const char *buf,short date,float b):base(a,buf)
{
this->date = date;
this->b = b;
}
short date;
float b;
};
int main()
{
//创建一个new_base对象
new_base tmp(100,"Xiaowu",12,3.14);
//测试显示数据
cout << tmp.a << endl;
cout << tmp.b << endl;
cout << tmp.buf << endl;
cout << tmp.date << endl;
return 0;
}
编译运行,结果如下所示:
6、继承中的析构函数
在继承中所有析构函数都会执行,先执行
派生类
析构,再执行基类
析构
#include <iostream>
#include <string.h>
using namespace std;
//继承中的析构函数:执行顺序与构造函数是相反的
//在继承中所有的析构函数都会执行,先执行派生类析构,再执行基类析构
//设计基类(父类)
class base
{
public:
~base() //base的析构
{
cout << "~base()" << endl;
}
};
//设计一个派生类(子类)
class new_base : public base
{
public:
~new_base()
{
cout << "~new_base()" << endl;
}
};
int main()
{
//创建一个new_base对象
new_base a;
return 0;
}
编译运行,结果如下:
7、继承中的拷贝构造问题
#include <iostream>
#include <string.h>
using namespace std;
//继承中的析构函数:执行顺序与构造函数是相反的
//在继承中所有的析构函数都会执行,先执行派生类析构,再执行基类析构
//设计基类(父类)
class base
{
public:
base()
{
p = new char[1024]; //分配一块堆空间
}
~base() //base的析构
{
delete []p; //释放空间
cout << "~base()" << endl;
}
private:
char *p;
};
//设计一个派生类(子类)
class new_base : public base
{
public:
new_base()
{
q = new int; //分配一块堆空间
}
~new_base()
{
delete q; //释放空间
cout << "~new_base()" << endl;
}
private:
int *q;
};
int main()
{
//创建一个new_base对象
new_base a;
//调用拷贝构造函数
new_base b = a;
return 0;
}
编译运行,将会出现问题,分析如下所示:
重写继承中的拷贝构造函数:
#include <iostream>
#include <string.h>
using namespace std;
//继承中的析构函数:执行顺序与构造函数是相反的
//在继承中所有的析构函数都会执行,先执行派生类析构,再执行基类析构
//设计基类(父类)
class base
{
public:
base()
{
p = new char[1024]; //分配一块堆空间
cout << "base() &p" << (void *)p << endl;
}
base(int size)
{
p = new char[size]; //分配一块堆空间
cout << "base() &p" << (void *)p << "size" << size << endl;
}
~base() //base的析构
{
cout << "~base() &p: " << (void *)p << endl;
delete []p; //释放空间
}
private:
char *p;
};
//设计一个派生类(子类)
class new_base : public base
{
public:
new_base()
{
q = new int; //分配一块堆空间
cout << "&q" << (void *)q << endl;
}
//重写new_base的拷贝构造函数
new_base(new_base &t):base(4096)
{
cout << "new_base(new_base &t)" << endl;
//让 q 指向新的堆空间
q = new int;
//打印分配的堆空间地址
cout << "&q: " << (void *)q << endl;
//让 p 也指向新的堆空间
//p = new char[1024]; //不可以调用基类的私有成员
}
~new_base()
{
cout << "~new_base() &q: " << (void *)q << endl;
delete q; //释放空间
}
private:
int *q;
};
int main()
{
//创建一个new_base对象
new_base a;
//调用 new_base 拷贝构造函数
//注意:不管是拷贝构造函数还是构造函数都是 先调用基类,再调用派生类
//而析构函数是 先调用派生类,再调用基类
new_base b = a;
return 0;
}
编译运行,结果如下所示:
练习4:完成下述类中的,构造函数,析构函数,拷贝构造函数等接口。
//设计基类(父类)
class base
{
private:
int size;
char *p; //指向一块 size 大小的堆空间
};
//设计一个派生类(子类)
class new_base : public base
{
private:
int *q; //指向一块 int 类的堆空间
};
#include <iostream>
#include <string.h>
using namespace std;
//设计基类(父类)
class base
{
private:
int size;
char *p; //指向一块 size 大小的堆空间
public:
//base的带参构造函数
base(int size):size(size)
{
p = new char[this->size];
//打印分配的堆空间及大小
cout << "base: (p)" << (void *)p << ",size: " << this->size << endl;
}
//重写base的拷贝构造函数
base(base &t)
{
this->size = t.size;
this->p = new char[t.size];
cout << "base(base &t): (p)" << (void *)this->p << ",size: " << this->size << endl;
}
//base 的析构函数
~base()
{
//打印释放的堆空间地址
cout << "~base: (p)" << (void *)p << endl;
delete []p;
}
};
//设计一个派生类(子类)
class new_base : public base
{
private:
int *q; //指向一块 int 类的堆空间
public:
//new_base的构造函数
new_base(int size):base(size)
{
q = new int;
cout << "new_base: (q)" << (void *)q << endl;
}
//重写拷贝构造函数
new_base(new_base &t):base(t)
{
this->q = new int;
cout << "new_base(new_base &t): (q)" << (void *)this->q << endl;
}
//new_base的析构函数
~new_base()
{
cout << "~new_base: (q)" << (void *)q << endl;
delete q;
}
};
int main()
{
cout << "------------base-------------" << endl;
//创建一个base对象
base a(1024);
//基类进行调用拷贝构造
base b = a;
cout << "----------new_base-----------" << endl;
//创建一个base对象
new_base c(1024);
//基类进行调用拷贝构造
new_base d = c;
return 0;
}
编译运行,结果如下:
8、继承中的赋值问题
提示:必须拥有情缘关系的类才符合这种关系
1、
派生类可以赋值给基类,
基类不可以赋值给派生类。
(大的可以覆盖小的,小的不能覆盖大的)
2、
基类可以引用派生类,
派生类不能引用基类。
#include <iostream>
using namespace std;
//设计基类(父类)
class base
{
public:
base(int date):date(date)
{
}
void show_base()
{
cout << "date: " << date << endl;
}
private:
int date;
};
//设计一个派生类(子类)
class new_base : public base
{
public:
new_base(int date,float a):base(date),a(a)
{
}
void show()
{
this->show_base();
cout << "a: " << a << endl;
}
private:
float a;
};
int main()
{
base a(100);
new_base b(10086,3.14);
a.show_base();
a = b; //派生类 赋值给 基类 (大的 可以覆盖 小的)
a.show_base();
//b = a; //基类 赋值给 派生类,不可以 (小的 不可以覆盖 大的)
//基类 引用 派生类 可以
base &qq = b;
qq.show_base();
//派生类 引用 基类 不可以
//new_base &ww = a;
return 0;
}
编译运行,结果如下:
分析:
![](https://i-blog.csdnimg.cn/blog_migrate/38593a75648c0b026ceee854862948ff.png)
9、继承方式
(1)不管哪种继承方式都不会影响,子类(派生类)对 父 类 (基类)的访问权限 (保护,公有)(2)不同的继承方式,就相当于把 父类(基类),放到子 类(派生类)的那个区 .(3)类外只能访问,基类的公共继承的公有成员
10、继承方式的分类
class 派生类 : public 基类 -> 公有继承,相 当于把 基类放到 派生类的公有区class 派生类 : protected 基类 -> 保护继承,相等于把 基类放到 派生类的保护区class 派生类 : private 基类 -> 私有继承,相 当于把 基类放到 派生类的私有区
#include <iostream>
using namespace std;
class base
{
public:
//公有 所有人都可以访问
int a;
protected:
//保护 类内 和 子类 可以访问
int b;
private:
//私有 类内 可以访问
int c;
};
//公共继承
class pub_base:public base
{
public:
//子类访问父类的成员
void set_base()
{
a = 100;
b = 200;
//c = 300; 私有成员只有类内可以访问
}
};
//保护继承
class pro_base:protected base
{
public:
//子类访问父类的成员
void set_base()
{
a = 100;
b = 200;
//c = 300; 私有成员只有类内可以访问
}
};
//私有继承
class pri_base:private base
{
public:
//子类访问父类的成员
void set_base()
{
a = 100;
b = 200;
//c = 300; 私有成员只有类内可以访问
}
};
//由上面可以看出,不管哪种继承方式,都不会影响 子类 对 父类 的访问权限
int main()
{
//类外访问
//类外 只能访问,基类的公共继承的公有成员
pub_base a;
a.a = 100;
//a.b = 200; 不可以访问
//a.c = 300;
pro_base b;
//b.a = 100; 不可以访问
//b.b = 200; 不可以访问
//b.c = 300; 不可以访问
pri_base c;
//c.a = 100; 不可以访问
//c.b = 200; 不可以访问
//c.c = 300; 不可以访问
return 0;
}
不同的继承方式的访问权限
继承的方式练习题
![](https://i-blog.csdnimg.cn/blog_migrate/09b285af54156086dd310a9af123ded3.png)
11、私有继承 和 保护继承 的区别
私有和保护继承是应用在多继承中的。
如果不想 派派生类,访问基类的成员,则使用 私有继承。
如果想
派派生类,访问基类的成员,则使用保护 或 共用继承。
#include <iostream>
using namespace std;
//基类
class base
{
public:
char buf[100] = "1000,0000$"; //1000万
};
//派生类
/*
//公有继承
class new_base : public base
{
//所有人都可以访问这1000万
};
*/
//保护继承
class new_base : protected base
{
//只有自己 和 子类 可以访问
};
//私有继承
class new_base1 : private base
{
//只有自己可以访问,据为己有
};
//派派生类
class new_new_base : public new_base
{
public:
void pf()
{
cout << buf << endl; //可以访问基类的成员
}
};
class new_new_base1 : public new_base1
{
public:
void pf()
{
//cout << buf << endl; //不可以访问基类的成员
cout << "new_new_base1 pf()" << endl;
}
};
int main()
{
new_new_base a;
a.pf();
new_new_base1 b;
b.pf();
return 0;
}
编译运行,结果如下所示: