一个类可以派生出其他的类,被派生的类称为派生类,派生派生类的类称为基类
派生类拥有基类的所有属性和方法:
以及派生类的3种继承方法过后里面的3中标签中的属性和方法会有什么改变
公开继承:私有成员隐藏,其他成员不变
受保护继承:私有成员隐藏,其他成员变成受保护
私有继承:私有成员隐藏,其他成员变成私有成员
在这个过程中,做了2个练习题来练习了一下各种继承的各种变化中间出现一个问题:想要从公开变成私有或者受保护很简单,只需要私有或者受保护继承即可,但是反过来想要从私有/受保护变成公开的话,公开继承是做不到的
这个时候,我们采用了一个特殊的方法,直接在派生类当中的公开标签中重新写一个同名函数,在该同名函数中,去调用基类的受保护方法(私有方法无法调用,因为继承后被隐藏)
这种方法叫做:函数的重写
什么叫函数重写:派生类允许重新定义基类当中的公开/受保护方法,但是注意,仅仅是重新定义。也就是说声明部分不能更改
声明部分不能更改意味着:函数的返回值和形参列表不能改变(我们的系统当中,函数返回值类型更改的话问题不是很大)
注意函数重写和函数重载的区别:
函数重写:函数仅仅重新定义
函数重载:函数仅仅函数名相同,参数类型必须不同
注意:一旦函数重写过后,从基类继承过来的同名函数就会消失(所谓重写就是拿着继承过来的东西重新定义)
注意:如果需要对基类的方法进行函数重载的话,注意先对他进行函数重写,否则编译报错
#include <iostream>
using namespace std;
class Base{
public:
virtual void func(){
cout << "基类方法" << endl
}
};
class Dervied1:public Base{
public:
void func(){
cout << "派生类1方法" << endl;
}
};
class Dervied2:public Base{
public:
void func(){
cout << "派生类2方法" << endl;
}
};
void f(Base* b){
b->func();
}
int main(){
Base b;
Dervied1 d1;
Dervied2 d2;
Base* b1 = &d1; //这种写法很少见
Base* b2 = new Dervied2;//常见写法
b1->func();
b2->func();
f(&d2);
return 0;
}
虚函数
一个只有方法,没有属性的类,他的大小永远是1
函数由于存在于代码段,是不会占用内存的
但是一旦为其中任何一个函数加上virtual关键字,该类就会瞬间变成8个字节大小,说明该类当中多了一个”指针“
那么,这个多出来的指针指向了哪里呢?
一旦一个类当中有任何一个方法被声明称虚方法之后,该类就需要有一张虚函数列表来保存所有的虚函数。
所以,多出来的指针其实就是指向了虚函数列表中的第一个函数的函数指针。
所以,在继承过程当中,本来是将函数继承过来的,一旦该函数是虚函数的话,就会将保存了该虚函数的虚表整体继承过来,基类和派生类共享该虚表
当派生类重写基类的虚函数的时候,基类的虚表当中的函数就会发生相应的改变,那么此时,如果基类指向了派生类的话,就会优先调用虚表当中的方法,由于虚表中的方法已经被派生类改变了,所以会调用派生类重写的方法,从而实现多态
#include <iostream>
using namespace std;
class Base{
public:
//virtual void func(){}
virtual void func() = 0 ; //纯虚函数,一旦拥有纯虚函数,base类就会变成纯虚类,无法产生对象
};
class Dervied:public Base{
public:
void func(){}
};
int main(){
Base* b = new Dervied;
return 0;
}
类型转换方式
#include <iostream>
using namespace std;
class Base{
public:
virtual void func(){};
};
class Dervied:public Base{
public:
int a;
void func(){}
};
int main(){
Base* b = new Dervied;
//派生类指针指向基类的时候,最正规的类型转换方式应该是使用关键字:dynamic_cast<目标类型>(目标对象)
Dervied* d = dynamic_cast<Dervied*>(new Base);
//d->a = 5;
Dervied* d2 = dynamic_cast<Dervied*>(b);
d2->a = 5;
return 0;
}
虚函数析构函数
#include <iostream>
using namespace std;
class Base{
public:
virtual void func(){};
Base(){
cout << "基类构造" << endl;
}
virtual ~Base(){
cout << "基类析构" << endl;
}
};
class Dervied:public Base{
public:
Dervied(){
cout << "派生类构造" << endl;
}
~Dervied(){
cout << "派生类析构" << endl;
}
};
int main(){
Base* b = new Dervied;
delete b;
return 0;
}
工厂模式
/*
多态的具体应用:多态的主要用途就是各种不同的设计模式,我们在有意无意间使用多态的地方,其实都是设计模式
简单工厂模式:
首先,有一个工厂类,专门生产制造工具
生产出来的制造工具可以用来制造不同的产品
再有一个操作者类,他的目的是最终拿到不同的产品
他的实现过程就是:调用工厂类当中的生产工具的方法,拿到具体的工具去产生不同的产品
那么简单工厂模式该怎么写呢:
① 先要有一个工厂类
② 工厂类里面要有一个产生各种不同工具的方法
这里面不同的工具就是多态
先有一个工具基类
然后有多种不同的工具继承自该基类
工厂在调用生产工具的方法的时候,只需要该方法的返回值
该方法的返回值必定是一个工具基类指针
③ 操作者类当中存放一个工厂类对象即可进行操作
*/
/*
使用简单工厂模式实现一个简单的+ - * /的计算器
工具类是谁?
加减乘除4则运算为4个工具,因为这4个工具要制造加减程序4个运算的结果
所以工厂类就是计算器:计算器生成工具的方法:就是根据不同的运算符返回不同的工具的过程
*/
#include <iostream>
using namespace std;
class Operator{
int x;
int y;
public:
void setX(int x){this->x = x;}
void setY(int y){this->y = y;}
int getX(){return x;}
int getY(){return y;}
virtual double calculate() = 0;
virtual ~Operator(){}
};
class OperatorAdd:public Operator{
public:
double calculate(){
return getX() + getY();
}
};
class OperatorSub:public Operator{
public:
double calculate(){
return getX() - getY();
}
};
class OperatorMul:public Operator{
public:
double calculate(){
return getX() * getY() * 1.0;
}
};
class OperatorDiv:public Operator{
public:
double calculate(){
return getX() / (getY() * 1.0);
}
};
class Calculator{
public:
Operator* getOperator(char ch);
};
Operator* Calculator::getOperator(char ch){
switch(ch){
case '+':
return new OperatorAdd;
case '-':
return new OperatorSub;
case '*':
return new OperatorMul;
case '/':
return new OperatorDiv;
default:
return NULL;
}
}
int main(){
int a = 0,b = 0;
char ch = 0;
double res = 0;
Calculator cal;
while(1){
cout << "请输入运算表达式:";
cin >> a >> ch >> b;
Operator* oper = cal.getOperator(ch);
oper->setX(a);
oper->setY(b);
res = oper->calculate();
cout << "运算结果为:" << res << endl;
delete oper;
}
return 0;
}