继承的概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
意义
可以实现代码复用,减少重复代码的劳动量
继承是实现多态的必要条件
继承本身就是为了实现多态的,顺便实现了代码复用
我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。
这个时候我们就可以考虑利用继承的技术,减少重复代码
称呼
一个类B 继承来自 类 A 我们一般称呼
A类:父类 基类
B类: 子类 派生类
B继承自A A 派生了B
继承定义
基本语法
class 子类名称:继承方式 父类名称
{
子类新增的成员;
}
class B:public A
{
}
示例代码
#include <iostream>
#include <string>
using namespace std;
class person
{
public:
string name; // 姓名
string sex; // 性别
int age; // 年龄
public:
person(string name,int age,string sex):name(name),age(age),sex(sex)
{
cout << "父类有参构造" << endl;
}
person()
{
name = "未设置姓名";
age = -1;
sex = "沃尔玛塑料袋";
cout << "父类无参构造" << endl;
}
~person()
{
cout << "我是父类的析构" << endl;
}
};
class student :public person{
public:
int id;
student(string name, string sex , int age, int id)
: person(name, age , sex), id(id)
{
cout << "子类有参构造" << endl;
}
student()
{
name = "未设置姓名";
age = -1;
sex = "沃尔玛塑料袋";
id = -1;
cout << "子类无参构造" << endl;
}
~student()
{
cout << "我是子类的析构" << endl;
}
public:
void show_date()
{
// 子类内调用父类的成员属性
cout << "姓名" << name << endl; // 直接使用 子类没有重名的情况下 可以使用
cout << "年龄" << person::age << endl; // 使用父类做区分 子类有重名的情况下 可以使用
cout << "性别" << this->sex << endl; // 和第一种一样
//
cout << "学号" << this->id << endl;
}
};
int main(int argc, char const *argv[])
{
student s1;
s1.name = "张三";
s1.person::age=10;
s1.sex="1";
s1.id=10;
s1.show_date();
}
1、子类如何访问父类的私有成员
子类中会继承父类中所有成员 ,包括私有成员,只不过在子类中不能直接访问父类私有成员
需要父类提供公有的函数来访问父类的私有成员
2、当父类 和 子类 函数名冲突时 咋办
当父子类中出现了同名的函数时,访问来也不会冲突
即使形参不同,也不构成重载关系 原因是两个函数不在同一个空间内
如果想访问父类的成员 需要加 类名 :: 来修饰
示例代码
#include <iostream>
#include <string>
using namespace std;
class person
{
//父类私有成员
private:
string name; // 姓名
string sex; // 性别
int age; // 年龄
//父类使用函数调用父类私有成员
public:
void set_name(string name)
{
this->name = name;
}
};
class student:public person
{
private:
public:
//1、子类如何访问父类的私有成员
void set_data(string name,string sex,int age)
{
person::set_name(name);
}
//2、当父类 和 子类 函数名冲突时 咋办
void set_name(string name)
{
person::set_name(name);//如果想访问父类的成员 需要加 类名 :: 来修饰
}
};
int main(int argc, char const *argv[])
{
cout << "hello world" << endl;
return 0;
}
基类对象初始化
在子类的构造函数中,通常需要在初始化列表中显式调用基类的构造函数,以完成对基类成员的初始化。例如:
// 在继承时,需要在子类的构造函数的初始化表中 显性的调用父类的构造函数 来完成对父类成员的初始化
格式
构造函数名(int val_1 , int val_2): class_A(val_1 , val_2);
类外访问:
对象名.基类名::变量;
对象名.基类名::函数名(函数的实参表);
类内访问:
基类名::变量;
基类名::函数名(函数的实参表);
继承方式
示例代码;
如果父类内是public成员和protected成员的话,继承后会根据继承方式的改变而将权限变小,既符合我们上面所说的:基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected> private。,private成员是最为特殊的,无论你是以哪一种方式继承都是在子类中不可见。
其实我们在平时使用的时候只会用到public继承方式,其他的两种继承方式是很少使用的
实际开发中 一般继承都采用 pubilc
继承方式
如果不写继承方式,默认使用的都是 private
方式继承
1、子类中会继承父类中所有成员 ,包括私有成员,只不过在子类中不能直接访问父类私有成员
需要父类提供公有的函数来访问父类的私有成员
2、当父子类中出现了同名的函数时,访问来也不会冲突
即使形参不同,也不构成重载关系 愿意是两个函数不在同一个空间内
如果想访问父类的成员 需要加 类名 :: 来修饰
类外访问:
对象名.基类名::变量;
对象名.基类名::函数名(函数的实参表);
类内访问:
基类名::变量;
对象名.基类名::函数名(函数的实参表);
代码示例