一、继承的基本概念
继承使得C++能够从已有的类派生出新的类,而派生类继承了原有类的特征,包括方法。被继承者称为父类或基类,继承者称为子类或派生类。
继承的目的:
- 实现代码的重用性
- 建立父类和子类之间的联系
- 在实现多态的时候,需要通过继承,实现子类对父类函数的重写
继承的格式:
class 类名:继承方式 类名
{
子类的拓展;
}
继承的方式:
public 公有继承、protected 保护继承、private 私有继承
示例:
#include <iostream>
using namespace std;
//封装 人 类 父类/基类
class Person
{
private:
string name;
int age;
public:
//无参构造函数
Person()
{
cout << "父类的无参构造函数" << endl;
}
//有参构造
Person(string name, int age):name(name),age(age)
{
cout << "父类的有参构造函数" << endl;
}
};
//封装 学生 类 共有继承人 类
class Stu:public Person //子类 、派生类
{
private:
int id;
int math;
public:
//无参构造函数
Stu()
{
cout << "子类的无参构造函数" << endl;
}
//有参构造函数
Stu(string name, int age, int id, int math):Person(name,age),id(id),math(math)
{
cout << "子类的有参构造函数" << endl;
}
};
int main()
{
Stu s("zhangsan",12,1001,78);
return 0;
}
二、继承中的特殊成员函数
构造函数:
父类的初始化必须赶在子类之前,换句话说,先调用父类的构造函数,再调用子类的构造函数。
析构函数:
析构函数调用的顺序:先调用子类的析构函数,再调用父类的析构函数。
先构造的 后析构。 后构造的先析构。
拷贝构造函数:
父类的拷贝构造函数会继承到子类中,在子类的拷贝构造函数中使用父类的拷贝构造函数,来完成子类从父类继承下来的成员的拷贝工作。
如果涉及深拷贝,则需要在子类和父类各自完成深拷贝工作。
拷贝赋值函数:
父类的拷贝赋值函数会继承到子类中,在子类的拷贝赋值函数中使用父类的拷贝赋值函数,来完成子类从父类继承下来的成员的赋值工作。
如果涉及深拷贝,则需要在子类和父类各自完成深拷贝工作。
示例:
#include <iostream>
using namespace std;
//封装 人 类 父类/基类
class Person
{
private:
string name;
protected:
int age;
public:
int h;
public:
//无参构造函数
Person()
{
cout << "父类的无参构造函数" << endl;
}
//有参构造
Person(string name, int age, int h):name(name),age(age),h(h)
{
cout << "父类的有参构造函数" << endl;
}
//拷贝构造函数
Person(const Person & other):name(other.name),age(other.age),h(other.h)
{
cout << "父类的拷贝构造函数" << endl;
}
//拷贝赋值函数
Person & operator=(const Person &p)
{
name = p.name;
age = p.age;
h = p.h;
cout << "父类的拷贝赋值函数" << endl;
return *this;
}
void show()
{
cout << "父类的show" << endl;
}
};
//封装 学生 类 公有继承人 类
class Stu:public Person //子类 、派生类
{
private:
int id;
int math;
public:
//无参构造函数
Stu()
{
cout << "子类的无参构造函数" << endl;
}
//有参构造函数
Stu(string name, int age, int h, int id, int math):Person(name,age,h),id(id),math(math)
{
cout << "子类的有参构造函数" << endl;
}
//拷贝构造函数
Stu(const Stu & s):id(s.id),math(s.math),Person(s)
{
cout << "子类的拷贝构造函数" << endl;
}
//拷贝赋值函数
Stu & operator=(const Stu & s)
{
Person::operator=(s);
id = s.id;
math = s.math;
cout << "子类的拷贝赋值函数" << endl;
return *this;
}
void show()
{
cout << "子类的show" << endl;
cout << h << endl; //通过共有继承,类外、子类可以访问父类共有成员
cout << age << endl; //通过共有继承,子类可以访问父类保护成员,类外不可以访问
//cout << name << endl;//通过共有继承,子类不可访问父类私有成员,类外不可以访问
}
};
int main()
{
Stu s("zhangsan",12,190,1001,78);
Stu s2=s;
Stu s3;
s3 = s2;
// s.show();
// s.Person::show();
return 0;
}
三、总结
父类的初始化必须赶在子类之前,换句话说,先调用父类的构造函数,再调用子类的构造函数。
当父类的函数和子类的函数是同名同类型时,不会报错,原因是作用域不同,如果子类实例化出一个对象,这个对象调用该函数,调用的是子类的函数,如果想调用父类中函数。则需要加上类名和作用域限定符。