本篇文章的内容为c++进阶部分,若有困惑,请先返回复习前面的知识
目录
继承和派生类的概念
继承是使代码可以复⽤的最重要的⼿段,它允许我们在保持原有 类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类。
class Student
{
public:
// 进⼊校园 / 图书馆 / 实验室刷⼆维码等⾝份认证
void identity()
{
// ...
}
// 学习
void study()
{
// ...
}
protected:
string _name = "peter";// 姓名
// 地址
string _address; //相同的部分
string _tel;
int _age = 18;
int _stuid;
};
class Teacher
{
public:
// 进⼊校园 / 图书馆 / 实验室刷⼆维码等⾝份认证
void identity()
{
// ...
} // 授课
void teaching()
{
//...
}
protected:
string _name = " 张三 ";// 姓名
// 年龄
int _age = 18;
string _address; // 相同部分
string _tel;
string _title;
};
那么以上的代码就是继承
说到继承就得先给大家科普一下两个概念
基类:说白了就是父类
派生类:说白了就是子类
那么下文的内容我将会使用父类,子类来代替基类和派生类
那么从上面的两串代码中我们采取相同的那部分就可以重新创造出一个类,这个类有两个类中相同的部分,因此我们叫它父类
class Person
{
public:
// 进⼊校园 / 图书馆 / 实验室刷⼆维码等⾝份认证
void identity()
{
cout << "void identity()" <<_name<< endl;
}
protected:
string _name = " 张三 ";
string _address;
string _tel;
int _age = 18;
};
继承定义
定义格式
class 派生类 :public 基类
// 子类 继承方式 父类
{
代码语句;
}
举个例子
class sudent : public person
{
public:
int _stuid;//学号
int _major;//专业
}
继承方式的种类
在讲继承种类之前,我们先来复习一下访问方式(即访问限定符)。
访问方式:private、protected、public
其实继承的种类也和访问方式一样,也是private、protected、public三种类型
继承基类成员访问⽅式的变化
那么这里有九种变化方式,这里我也总结了一下一共分为两类
第一类:派生类的任何方式都不能访问基类的私有成员,如果派生类硬要访问基类的私有成员,那么只能将基类中的private修饰符改成protected修饰符
第二类:基类的其他成员在派⽣类的访问⽅式==Min(成员在基类的访问限定符,继承⽅式),public >protected> private
举个例子:基类中的public成员被派生类以protected的方式继承,那么它在派生类中就是protected成员
其中最常用的两种是
继承类模板
template<class T>
class stack : public std::vector<T>
{
public:
void push(const T& x)
{
vector<T>::push_back(x);
}
void pop()
{
vector<T>::pop_back();
}
const T& top()
{
return vector<T>::back();
}
bool empty()
{
return vector<T>::empty();
}
};
基类和派⽣类间的转换
切片操作
切片操作:public继承的派⽣类对象可以赋值给基类的指针/基类的引⽤
注意事项:
1.基类对象不能赋值给派⽣类对象。
2.基类的指针或者引⽤可以通过强制类型转换赋值给派⽣类的指针或者引⽤。
继承中的作⽤域
隐藏规则
1.继承体系中的基类和派生类都有独立的作用域
2.隐藏:派⽣类和基类中有同名成员,派⽣类成员将屏蔽基类对同名成员的直接访问
隐藏:函数名相同,参数相同,函数名相同,参数不同
3.需要注意的是成员函数的隐藏,只需要函数名相同就构成隐藏。
4.注意在实际中在继承体系⾥⾯最好不要定义同名的成员。
隐藏和函数重载的区别
函数重载必须在同一个作用域
派⽣类的默认成员函数
1. 派⽣类的构造函数必须调⽤基类的构造函数初始化基类的那⼀部分成员。
2. 派⽣类的拷⻉构造函数必须调⽤基类的拷⻉构造完成基类的拷⻉初始化。
3. 派⽣类的operator=必须要调⽤基类的operator=完成基类的复制。
4. 派⽣类的析构函数会在被调⽤完成后⾃动调⽤基类的析构函数清理基类成员。
5.派⽣类对象初始化先调⽤基类构造再调派⽣类构造。
6. 派⽣类对象析构清理先调⽤派⽣类析构再调基类的析构。
总结:1. 子类的构造、拷贝构造、operator= 都必须要调用父类的
2. 子类对象的初始化先调用子类再调用父类
3. 子类对象析构先调用子类析构,再调用父类析构
继承与友元
有缘关系不能被继承,即基类友元不能访问派⽣类私有和保护成员
继承与静态成员
基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。
⽆论派⽣出多少个派⽣类,都 只有⼀个static成员实例。
举例:
class Person
{
public:
string _name;
static int _count;
};
int Person::_count = 0;
class Student : public Person
{
protected:
int _stuNum;
};
int main() {
Person p;
Student s;
// 这⾥的运⾏结果可以看到⾮静态成员 _name 的地址是不⼀样的
// 说明派⽣类继承下来了,⽗派⽣类对象各有⼀份
cout << &p._name << endl; cout << &s._name << endl;
cout << &s._name << endl;
// 这⾥的运⾏结果可以看到静态成员 _count 的地址是⼀样的
// 说明派⽣类和基类共⽤同⼀份静态成员
cout << &p._count << endl; cout << &s._count << endl;
cout << &s._count << endl;
// 公有的情况下,⽗派⽣类指定类域都可以访问静态成员
cout << Person::_count << endl;
cout << Student::_count << endl;
return 0;
}
多继承及其菱形继承问题
继承的种类
单继承:⼀个派⽣类只有⼀个直接基类
多继承::⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承
其中,多继承对象在内存中的模型,先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯
菱形继承:多继承的一种特殊情况,可以看出菱形继承有数据冗余和⼆义性的问题
虚继承
概念:虚拟继承一个类
class Student : virtual public Person
{
protected:
int _num; // 学号
};
继承和组合
public继承是⼀种is-a的关系。
1.组合是一种has-a的关系
2.继承允许你根据基类的实现来定义派⽣类的实现。
3.对象组合是类继承之外的另⼀种复⽤选择。
4.优先使⽤组合,⽽不是继承。
has-a的关系
is-a的关系
本篇文章的内容到此结束,我们下一篇文章再见!!
都看到这里了,给个三联再走呗,谢谢啦!!!