继承方式
公有继承:基类公有和保护成员在子类中仍然是公有和保护。基类私有成员仍为基类私有。
私有继承:基类公有和保护成员变为子类私有成员。基类私有成员仍为基类私有。
保护继承:基类公有和保护成员变为子类保护成员。基类私有成员仍为基类私有。
(保护成员能被子类访问,但是不能被子类和父类的对象访问)
总结:
1.能不能被子类访问,看在基类中是什么成员。基类的公有和保护成员被继承后能被子类访问。
2.子类的对象能访问的只有公有继承过来的基类的公有成员。
继承写法
//继承写法。继承方式public可选,不写默认为private
Class sportCar:public Car,public Ship
{
public:
private:
};
保护(protect)对象
//protected在没有继承的时候和private一样
//发生公有继承时,protected在派生类中可以被访问
区别(public继承时)
//private子类和子类的对象中都不能访问
//protected子类中可访问,子类的对象中不可访问
构造函数
class Human{
private:
string name;
public:
Human(){}
Human(string str){name=str;}
};
class Man:public Human,public animal{
public:
Man(int n,string str,int x):animal(x),Human(str){num=n;}//子类调用基类构造函数
Man(){}
private:
int num;
};
//子类默认调用基类的默认构造函数,如果基类没有默认构造函数,那么子类必须显式调用基类某个构造函数
//构造函数调用顺序:1.先基类的,2.再数据成员为类对象的这些类的构造函数,3.最后本类自己的
//1.基类顺序为继承时的说明顺序,如上先Human再animal
//2.成员为类的调用顺序是类中定义顺序
//“先父母,再客人,后自己”
析构函数
//调用顺序与构造函数相反,先自己,后父母
命名冲突
Class sportCar:public Car,public Ship
{
public:
Car::move(){}//多继承命名冲突解决办法:使用域解析符
Ship::move(){}
private:
using Car::move;//使用using可以把基类的public成员变为private或protect,隐藏起来
};
sportCar p;
//p.move();有歧义的分不清用来自哪个基类的move,所以加上基类名
p.Car::move();
p.Ship::move();
//多继承中基类变量重名不会被覆盖
class Human{public:int a;};
class Human2{public:int a;};
class people:public Human,public Human2{public:int a;};
//现在有三个不同的a
//x.a
//x.Human::a
//x.Human2::a
虚基类(从不同路径继承同一个类,让其中的变量都是同一个)
//people的两个基类都继承了同一个类,这样
class Base{public:int a;};
class Human:public Base{};
class Human2:public Base{};
class people:public Human,public Human2{};
//a从两条路径被继承下来,一共有两个不同的a
people x;
//x.a;//错误
//x.Base::a;//错误
x.Human::a;
x.Human2::a;
//虚继承
//如果想让所有的a都是同一个,可以用虚继承
class Base{public:int a;};
class Human:virtual public Base{};//继承方式前加virtual
class Human2:virtual public Base{};
class people:public Human,public Human2{};
//这四个a是同一个
people x;
x.a=1;
x.Human::a=2;
x.Human2::a=3;
x.Base::a=4;
类型适应
基类对象A可以放的地方,都可以放上子类的对象B
三种情况:
1.B赋值给A
2.B初始化A的引用
3.B的地址赋给指向基类的指针