1.继承
解决问题:减少代码冗余(重复代码),让新写的代码可以重复使用已经有的代码,提高效率
何时使用:当子类是父类的一种特殊版本时,可以让子类继承父类
继承如何继承:子类去继承父类,会继承了父类的所有成员(数据成员和成员函数!)友元是否会被继承?友元是不会被继承的,没有传递性!父类的构造和析构不会被子类继承
//继承的格式
class 子类名:继承的方式 父类名
{
};
//继承的方式有3种,public,private,protected
1.1 子类继承父类的数据成员
父类的数据成员是私有的时候,类的外部不可访问,所以父类的数据成员放到protected中
1.2 子类继承父类的成员函数
子类可以继承父类除了构造和析构函数之外的成员函数
以下是一个以人作为父类,工人作为子类的继承方式是public的例子:
#include<iostream>
#include<string>
using namespace std;
//父类
class Person
{
public:
Person(string name = "", string sex = "")
{
cout << "Person(string,string)" << endl;
this->name = name;
this->sex = sex;
}
void show()
{
cout << "姓名为" << this->name << "的性别是:" << this->sex << endl;
}
private:
protected:
string name;
string sex;
};
//子类:
//子类继承父类的格式 --- class 子类名:继承的方式 父类名
//继承的方式有3种,一般用public
//继承的时候,子类继承了父类的数据成员
//父类的数据成员是私有的时候,类的外部不可访问,所以父类的数据成员放到protected中
//子类可以继承父类除了构造和析构函数之外的成员函数
class Worker :public Person
{
public:
Worker(string name="",string sex="",int salary=8000):Person(name,sex),salary(salary)
{
cout << "Worker()" << endl;
}
~Worker()
{
cout << "~Worker()" << endl;
}
void word()
{
cout <<"姓名为" << this->name << "的工人在工作...." << endl;
}
private:
int salary;
protected:
};
int main()
{
Worker worker("张三", "男", 9000);
worker.show();
worker.word();
return 0;
}
public继承:
1.父类的public成员:在子类内和类的外部都可以访问
2.父类的private成员:在子类中和类外都不可以访问
3.父类的protected成员:在子类中可以访问,类外不可以访问
private继承:
1.父类的public成员:在子类内可以访问,类的外部不可以访问
2.父类的private成员:在子类中和类外都不可以访问
3.父类的protected成员:在子类中可以访问,类外不可以访问
protected继承:
1.父类的public成员:在子类内可以访问,类的外部不可以访问
2.父类的private成员:在子类中和类外都不可以访问
3.父类的protected成员:在子类中可以访问,类外不可以访问
总结:父类的public成员只有采用public继承时才可以在类内类外都访问
父类的protected成员不管哪种继承方式,都只能在子类内访问
父类的private成员不管哪种继承方式,在子类内都不可以访问
故一般采用public继承
2.子类的构造函数和析构函数
2.1 子类的构造函数
在继承关系中,创建子类的对象,构造的执行顺序:先执行父类,再执行子类
在继承关系中,数据成员是谁声明的就谁去初始化,子类的构造函数只会初始化自己声明的数据成员,从父类继承的数据成员要由父类的构造函数初始化;如果不指定,就走父类的默认构造函数;如果要让它去做初始化的动作,就要指定执行的构造函数(用初始化列表的方式)
2.2 子类的析构函数
在继承关系中,释放子类对象,析构的顺序是先释放子类,再释放父类,即先构造的后析构
3.多层继承
A-->B-->C-->D
D继承C,C继承B,B继承A
人类-->工人类-->教师类
子类继承父类的成员函数和数据成员,当子类中有一个与父类成员函数同名出现时,用子类对象调用会执行子类的成员函数,从父类继承过来的成员函数被隐藏了(重定义)
如果要调用与父类同名的成员函数时,要指定类名:函数名();
总结:1.构造顺序:先父类再子类
2.析构顺序:先构造的后析构
3.隐藏(重定义):子类定义了一个与父类函数名相同的数据成员
何时需要重定义:当父类定义的函数无法实现子类的需求时
4.多重继承
人类-->工人类
-->农民类 --->农民工
农民工同时是工人和农民
在多重继承中,如果这个子类的两个父类里都有相同的数据成员,会出现访问不明确问题,用虚继承方法解决
#include<iostream>
#include<string>
using namespace std;
//父类A
class Person
{
public:
Person(string name = "", string sex = "")
{
cout << "Person(string,string)" << endl;
this->name = name;
this->sex = sex;
}
void show()
{
cout << "姓名为" << this->name << "的性别是:" << this->sex << endl;
}
private:
protected:
string name;
string sex;
};
//子类B:---virtual就是虚的意思
class Farmer :virtual public Person
{
public:
Farmer(string name = "", string sex = "", int filed = 5) :Person(name, sex), filed(filed)
{
cout << "Farmer()" << endl;
}
~Farmer()
{
cout << "~Farmer()" << endl;
}
void word()
{
cout << "姓名为" << this->name << "的农民在工作...." << endl;
}
private:
protected:
int filed;
};
//子类C:
class Worker :virtual public Person
{
public:
Worker(string name = "", string sex = "", int salary = 8000) :Person(name, sex), salary(salary)
{
cout << "Worker()" << endl;
}
~Worker()
{
cout << "~Worker()" << endl;
}
void word()
{
cout << "姓名为" << this->name << "的工人在工作...." << endl;
}
private:
protected:
int salary;
};
//子类D:
//在多重继承关系中,创建子类的对象,父类的执行顺序与初始化列表的顺序无关,与继承的顺序有关,谁先继承,先走谁的构造
class FarmerWorker :public Farmer,public Worker
{
public:
FarmerWorker(string name = "", string sex = "", int salary = 8000,int filed=2) :Worker(name, sex,salary), Farmer(name, sex, filed)
{
cout << "FarmerWorker()" << endl;
}
~FarmerWorker()
{
cout << "~FarmerWorker()" << endl;
}
void word()
{
cout << "姓名为" << this->name << "的农民工在工作...." << endl;
}
private:
protected:
};
int main()
{
Worker worker("张三", "男", 9000);
worker.show();
worker.word();
return 0;
}
类B继承于类A,类C继承于类A,类D继承于类B和类C;这样子就会导致类D中拥有两份的类A中的数据成员,访问的时候就会出现访问不明确的问题。
解决:类B虚继承类A,类C虚继承类A!