类的特点
继承:当一个类继承自另外一个类的时候,他会拥有被继承类的所有属性和方法
实现继承:类名 + :public/private/protected + 想要继承的类
被继承的类称为:基类
继承基类的类称为:派生类
继承过后,被继承的类中的方法和属性都会拥有,并且还可以自己扩展新的方法和属性,这就是面向对象编程的一大核心
派生类中之所以会拥有基类的所有类型和方法,原因在于,派生类在构建的时候,会构建一次基类,然后在构建派生类但是,又由于以上原因,基类和派生类等于说是两个不同的类,只不过基类被包含在派生类当中,所以,这两个类仅仅是包含和被包含的关系,并不是友元关系,所以派生类是无法访问基类的私有成员的
既然现在 使用基类的get,set方法就能够在派生类中访问基类的私有成员
那么,如何在派生类构建的同时,初始化基类的私有成员呢?
首先明确,想要初始化,肯定依靠构造函数但是,由于列表初始化是一个非常简单的赋值操作,所以针对基类中的私有成员,列表初始化的话依旧不能访问基类中的私有成员
之前说过,派生类在构建的时候,先会调用基类的构造函数。我们只需要利用这一点,在派生类构建基类的时候,让他调用的是基类的带参构造函数,就能够实现针对基类私有成员的初始化
那么,如何在派生类的构造函数当中,手动的调用基类的带参构造函数呢?
直接在派生类的构造函数当中的列表初始化位置,调用基类的带参构造函数
#include <iostream>
using namespace std;
class Manmal{
string name;
int age;
public:
Manmal(){
cout << "基类构造" << endl;
}
Manmal(string name,int age):name(name),age(age){
cout << "基类带参构造" << endl;
}
void show(){
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
}
void setName(string name){
this -> name = name;
}
void setAge(int age){
this->age = age;
}
};
class Human:public Manmal{
bool sex;
public:
Human(){
cout << "派生类构造" << endl;
}
//直接在派生类的构造函数当中的列表初始化位置,调用基类的带参的构造函数
Human(string name,int age,bool sex):
Manmal(name,age),sex(sex){
cout << "派生类带参构造" << endl;
}
void setSex(bool sex){
this ->sex = sex;
}
}
int main(){
Human h1;
h1.setName("张三");
h1.setAge(20);
h1.setSex(1);
Human h1("张三",20,1);
h1.show();
return 0;
}
public / private /protected
继承的时候使用的 public/private/protected 这3种继承方式有什么区别?
首先要知道,类中的成员不仅仅有公开成员和私有成员,还拥有一个叫做受保护成员
什么是受保护成员:
受保护成员在外部访问的时候,他的特性和私有成员一样
在继承过后的内部访问的时候,他的特性和公开成员一样
为什么受保护成员有这样的特性呢?我们要说一下继承的工作本质
首先明确:派生类本质上是有权访问基类中的所有属性和方法。(包括私有成员)
但是,为什么实际运行过程当中,私有成员是不能访问的呢?这是由于继承过程当中的隐藏功能
顺便也能了解一下 public/private/protected继承有什么区别
public 继承:
继承过后,基类的公开成员依旧是公开成员,基类的受保护成员依旧是受保护成员,基类的私有成员被隐藏(也就是说无法在派生类中直接访问,只允许通过基类当中的公开方法去访问)
protected 继承:
继承过后,基类的公开成员和受保护成员都会变成受保护成员,基类的私有成员被隐藏
private 继承:
继承过后,基类的公开成员和受保护成员变成私有成员,基类的私有成员被隐藏
总结下来:无论什么继承,基类的私有成员都会被隐藏而公开成员和受保护成员变化取决与继承方式
/*
通过继承导致的访问权限受阻的特性,实现以下功能
设计一个发动机类,内部包含加油的方法和启动的方法;
设计汽车类继承自发动机类
要求:发动机对象可以调动加油方法但是无法调用启动方法,汽车对象可以调用启动方法但是无法调用加油方法
*/
#include <iostream>
using namespace std;
class Engine{
protected:
void boostUp(){
cout << "启动" << endl;
}
public:
void addOil(){
cout << "加油" << endl;
}
};
class Car:protected Engine{
public:
void boostUp(){
Engine::boostUp();//受保护的方法通过受保护继承过来后,依旧是受保护的,允许在派生类中访问
}
};
int main(){
Engine e;
e.addOil();
// e.boostUp();
Car c;
// c.addOil();
c.boostUp();
return 0;
}
/*
通过继承导致的访问权限受阻的特性,实现以下功能
设计发动机类,内部包含加油和启动方法
设计轮胎类,内部包含跑的方法
设计传动系统类,继承自发动机类和轮胎类
设计汽车类,继承自传动系统类
要求:发动机对象可以调用 加油 和 启动
轮胎对象不能调用 跑
传动系统对象无法调用 加油 启动 和 跑
汽车对象可以调用启动方法并且让轮胎跑起来,但是不能调用加油
*/
#include <iostream>
using namespace std;
class Engine{
public:
void addOil(){
cout << "发动机加油" << endl;
}
void boostUp(){
cout << "发动机启动" << endl;
}
};
class Tyre{
protected:
void run(){
cout << "汽车让轮胎跑" << endl;
}
};
class Drive:protected Engine,public Tyre{
};
class Car:public Drive{
public:
void boostUp(){
Engine::boostUp();
Tyre::run();
}
};
int main(){
Engine e;
e.addOil();
e.boostUp();
Tyre t;
// t.run();
Drive d;
// d.addOil();
// d.boostUp();
// d.run();
Car c;
c.boostUp();
return 0;
}
多重继承
/*
关于多重继承:一个类可以同时继承自2个不同的类,自然,也就是在派生类中构建2个不同的基类而已,构建顺序从左到右
*/
#include <iostream>
using namespace std;
class Animal{
string name;
int age;
public:
Animal(){cout << "Animal构造" << endl;}
Animal(string name,int age):name(name),age(age){}
void show(){
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
}
};
class Human{
int height;
int weight;
public:
Human(){cout << "Human构造" << endl;}
Human(int height,int weight):height(height),weight(weight){}
void show(){
cout << "身高:" << height << "cm" << endl;
cout << "体重:" << weight << "斤" << endl;
}
};
class Zhangsan:public Animal,public Human{
public:
Zhangsan(string name,int age,int h,int w)
:Animal(name,age),Human(h,w)
{}
void show(){
Animal::show();
Human::show();
}
};
int main(){
Zhangsan zs("张三",20,180,150);
zs.show();
return 0;
}
多重继承的菱形继承问题
/*
关于多重继承的菱形继承问题
*/
#include <iostream>
using namespace std;
class Base{
int a;
public:
void setA(int a){this->a = a;}
int getA(){return a;}
};
class Dervied1:virtual public Base{
};
class Dervied2:virtual public Base{
};
class Dervied3:public Dervied1,public Dervied2{
public:
void show(){
//cout << a << endl;这样写有歧义
//方法① 明确该a是来自谁的
//cout << Dervied1::getA() << endl;
//cout << Dervied2::getA() << endl;
//方法2 采用虚拟继承的方式,在Dervied1和Dervied2继承Base的时候,采用虚拟继承的方式,虚拟继承后,菱形继承的问题当中,从同一个祖先基类当中继承过来的相同变量只会有一个
cout << getA() << endl;
}
};
int main(){
Dervied3 d3;
//d3.Dervied1::setA(1);
//d3.Dervied2::setA(2);
d3.setA(3);
d3.show();
return 0;
}