C++为什么要有继承
我们都知道很多类都有自己的数据成员以及函数,在编写程序时,会有很多类的拥有相同的数据成员和函数,为了节省时间以及代码量,我们把这些公共的数据和函数封装成一个类,后面的类只要继承这个类即可。
什么是继承
继承是面向对象复用的重要手段。继承是类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
例如:
1.继承方式和访问限定符的关系
继承的访问限定符有:
public / protected /private
三种继承关系下基类成员的在派生类的访问关系变化
- 基类的私有成员在派生类中不能被访问,如果一些基类成员不想被基类帝乡访问,但需要在派生类中访问,就定义为保护成员,可以看出保护成员限定符是因继承才出现的。
- public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
- protected/private继承是一个实现继承,基类的部分成员并未完全成为子类接口的一部分,是has-a的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。
- 不管是哪种继承方式,在派生类内部都可以访问基类的公共成员和保护成员,但基类的私有成员存在但是不能访问。
- 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
- 在实际运用中一般使用public继承,极少场景下使用protected/private继承。
继承与转换(public继承):
子类对象可以赋值给父类对象(切割/切片)
父类对象不能赋值给子类对象。
- 父类的指针或引用可以只想子类对象。
- 子类对象的指针或引用不能指向父类对象
class person
{
public:
void fun()
{
}
protected:
string _name;
};
class teacher:public person
{
public:
int _age;
};
int main()
{
person p;
teacher t;
p = t; //子类对象可以赋值给父类对象。
//t=p;不允许
person *p1 = &t; //父类的指针或引用可以指向子类对象
person &q1 = t;
teacher *p2 = (teacher*)&p; //子类的引用或指针不能指向父类对象,(可以强转类型之后完成)
teacher& q2 = (teacher&)p;
}
在继承体系中基类和派生类都有独立的作用域。
隐藏(重定义):子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问(在子类成员函数中,可以使用 基类::基类成员 访问)
派生了默认成员函数
在继承关系里面,在派生类中如果没有显示定义六个默认成员函数,编译系统则会默认合成这六个成员函数。
当基类构造函数需要外部传递参数才能进行初始化时,派生类必须显式定义构造函数,为基类传递参数;基类如果不需要传递或者可以不传递参数,派生类可以不用显式定义构造函数。
lass person
{
public:
person(const char* name) //基类构造函数
:_name(name)
{}
person(const person& p) //基类拷贝构造
:_name(p._name)
{}
person& operator=(const person& p) //赋值运算符重载
{
if (this != &p)
{
_name = p._name;
}
return *this;
}
~person() //基类析构
{}
protected:
const char* _name;
};
class student :public person
{
public:
student(const char* name, int num) //派生类构造函数
:person(name)
, _num(num)
{}
student(const student& s) //派生类拷贝构造
:person(s)
, _num(s._num)
{}
student & operator=(const student& s) //派生类赋值运算符重载
{
if (this != &s)
{
person::operator=(s);
_num = s._num;
}
return *this;
}
~student() //派生类析构
{}
protected:
int _num;
};