目录
继承
基本语法
- 好处:减少重复代码
- 公式:
class A :public B {...}
- A类称为子类、派生类
- 包括两大部分:
- 从基类继承过来的
- 子类自己添加的内容
- 包括两大部分:
- B类称为父类、基类
#include <iostream>
// 基类
class Animal {
public:
void eat() {
std::cout << "动物正在进食" << std::endl;
}
void sleep() {
std::cout << "动物正在睡觉" << std::endl;
}
};
// 派生类
class Cat : public Animal {
public:
void meow() {
std::cout << "猫正在喵喵叫" << std::endl;
}
};
// 另一个派生类
class Dog : public Animal {
public:
void bark() {
std::cout << "狗正在汪汪叫" << std::endl;
}
};
int main() {
Cat cat;
cat.eat();
cat.sleep();
cat.meow();
Dog dog;
dog.eat();
dog.sleep();
dog.bark();
return 0;
}
继承方式
class A : 继承方式 B {...}
- 继承方式:
- public:公共继承
- protected:保护继承
- private:私有继承
- 所以B私有继承A,C公共继承B,结果是C访问不到A中的内容
子类大小sizeof
#include<iostream>
using namespace std;
class Base
{
public:
int a;
protected:
int b;
private:
int c; // 虽然son访问不到,但也会继承到son中
};
class son : public Base
{
public:
int d;
};
int main()
{
cout << sizeof(son) << endl; //16 = a+b+c+d 即4(int)*4(abcd)=16
}
构造和析构函数的顺序
- 先进行父类的构造,再进行子类的构造
- 先进行子类的析构,再进行父类的析构
继承中同名成员的处理
- 子类和父类里有成员变量的名字相同时,默认访问的是子类中的
- 若要访问父类中的,则多加上父类的作用域:
s.Base::a
class Base
{
public:
int a = 100;
};
class son : public Base
{
public:
int a = 200;
};
int main()
{
son s;
cout << s.a << endl; // 200
cout << s.Base::a << endl; // 100
}
多继承(不推荐使用)
- 语法:
class A : 继承方式 B, 继承方式 C, ... {...}
- 不同的父类之间用逗号’,'相隔
- 同样的,有变量名冲突,在使用时加上作用域即可
菱形继承(解决子类继承两份相同的数据,从而导致资源的浪费)
- 用到虚继承和virtual
多态
概念
- 两类
- 静态多态:函数重载、运算符重载,复用函数名 —>函数地址早绑定(编译阶段)
- 动态多态:派生类、虚函数、纯虚函数,实现运行时多态 —>函数地址晚绑定(运行阶段)
动态多态满足条件:有继承关系、子类重写父类的虚函数
- 重写:函数返回类型、函数名、参数列表 完全一致
使用:
父类的指针或引用指向子类对象
#include <iostream>
using namespace std;
// 基类
class Shape {
public:
virtual void draw() {
cout << "Shape::draw()" << endl;
}
};
// 派生类
class Circle : public Shape {
public:
void draw() {
cout << "Circle::draw()" << endl;
}
};
// 派生类
class Square : public Shape {
public:
void draw() {
cout << "Square::draw()" << endl;
}
};
int main() {
// 创建派生类对象
Circle circle;
Square square;
// 声明指向基类的指针
Shape *shapePtr;
// 指向 Circle 对象的指针
shapePtr = &circle;
shapePtr->draw(); // 调用虚函数,将调用 Circle::draw()
// 指向 Square 对象的指针
shapePtr = □
shapePtr->draw(); // 调用虚函数,将调用 Square::draw()
return 0;
}
原理
练习1——计算器类
#include<iostream>
using namespace std;
class AbstractCalculator
{
public:
virtual int getresult()
{
return 0;
}
int a;
int b;
};
//加法
class AddCalculator:public AbstractCalculator
{
public:
int getresult()
{
return a+b;
}
};
//乘法
class SubCalculator:public AbstractCalculator
{
public:
int getresult()
{
return a*b;
}
};
int main()
{
// 法一:本地变量
AddCalculator add;
AbstractCalculator *ptr1 ;
ptr1 = &add;
ptr1->a = 1;
ptr1->b = 2;
cout << ptr1->getresult() << endl;
//法二:new到堆区
AbstractCalculator *ptr2 = new SubCalculator;
ptr2->a = 1;
ptr2->b = 2;
cout << ptr2->getresult() << endl;
delete ptr2;
}
纯虚函数和抽象类
- 语法:
virtual 返回值类型 函数名 (参数列表) = 0
- 当类中有了纯虚函数,这个类称为抽象类
抽象类特点:
- 无法实例化对象 —>即,
Base b
是会报错的- 子类必须重写抽象类中的纯虚函数,否则也为抽象类
class Base
{
public:
virtual void func() = 0;
};
class Son:public Base
{
public:
virtual void func() //有没有virtual都行
{
...
}
};
练习2——制作饮品
#include<iostream>
using namespace std;
class drink
{
public:
//煮水
virtual void boil() = 0;
//冲泡
virtual void brew() = 0;
//导入杯中
virtual void pour() = 0;
//加入辅料
virtual void put() = 0;
//制作饮品
void makedrink() //抽象类也可以定义其他东西(包括不是虚函数的其他成员函数)
{
boil();
brew();
pour();
put();
}
};
class coffee:public drink
{
public:
//煮水
virtual void boil()
{
cout << "咖啡-煮水" << endl;
}
//冲泡
virtual void brew()
{
cout << "咖啡-冲泡" << endl;
}
//导入杯中
virtual void pour()
{
cout << "咖啡-导入杯中" << endl;
}
//加入辅料
virtual void put()
{
cout << "咖啡-加入辅料" << endl;
}
};
class tea:public drink
{
public:
//煮水
virtual void boil()
{
cout << "茶-煮水" << endl;
}
//冲泡
virtual void brew()
{
cout << "茶-冲泡" << endl;
}
//导入杯中
virtual void pour()
{
cout << "茶-导入杯中" << endl;
}
//加入辅料
virtual void put()
{
cout << "茶-加入辅料" << endl;
}
};
int main()
{
drink *ptr1 = new coffee;
ptr1->makedrink();
delete ptr1;
drink *ptr2 = new tea;
ptr2->boil();
ptr2->brew();
ptr2->pour();
ptr2->put();
delete ptr2;
}
虚析构和纯虚析构
问题
:使用多态时,如果子类有东西开辟到堆区,那么父类指针在释放时无法调用到子类的析构析构代码—>所以子类开辟了堆区数据,在子类析构函数里实现对其数据的手动释放解决方式
:将父类中的析构函数改为虚析构、纯虚析构
虚析构和纯虚析构的共性
- 可以解决父类指针释放子类对象
- 都需要具体函数实现
- 里面好像不用写东西也可以,因为释放子类在堆区的东西的任务由子类的析构函数承担
区别
- 纯虚析构的类为抽象类,无法实例化对象
虚函数语法:virtual ~类名( ) {...}
纯虚析构语法:
virtual ~类名( ) = 0;
—>类内
类名::~类名( ) {...}
—>类外
练习3——电脑组装1
#include <iostream>
using namespace std;
// 抽象类
class CPU
{
public:
virtual void caclulate() = 0;
};
class VideoCard
{
public:
virtual void display() = 0;
};
class Memory
{
public:
virtual void storage() = 0;
};
// 电脑组装
class Computer
{
public:
// 构造函数
Computer(CPU *c, VideoCard *v, Memory *m)
{
cpu = c;
videocard = v;
memory = m;
}
// 成员函数
void work()
{
//让零件工作起来,调用接口
cpu->caclulate();
videocard->display();
memory->storage();
}
//析构函数,释放3个电脑零件
~Computer()
{
if(cpu!=nullptr)
{
delete cpu;
cpu = nullptr;
}
if(videocard!=nullptr)
{
delete videocard;
videocard = nullptr;
}
if(memory!=nullptr)
{
delete memory;
memory = nullptr;
}
}
private:
//三个电脑零件
CPU *cpu;
VideoCard *videocard;
Memory *memory;
};
// intel的零件
class intel_cpu : public CPU
{
public:
void caclulate()
{
cout << "intel cpu 在工作" << endl;
}
};
class intel_VideoCard : public VideoCard
{
public:
void display()
{
cout << "intel display 在工作" << endl;
}
};
class intel_Memory : public Memory
{
public:
void storage()
{
cout << "intel storage 在工作" << endl;
}
};
// lenovo的零件
class lenovo_cpu : public CPU
{
public:
void caclulate()
{
cout << "lenovo cpu 在工作" << endl;
}
};
class lenovo_VideoCard : public VideoCard
{
public:
void display()
{
cout << "lenovo display 在工作" << endl;
}
};
class lenovo_Memory : public Memory
{
public:
void storage()
{
cout << "lenovo storage 在工作" << endl;
}
};
int main()
{
//第一台电脑组装(法一)
//这三个电脑零件在Computer的析构函数里释放(也可以在下面的computer_ptr1后面释放)
CPU *intel_cpu_ptr = new intel_cpu;
VideoCard *intel_VideoCard_ptr = new intel_VideoCard;
Memory *intel_Memory_ptr = new intel_Memory;
Computer *computer_ptr1 = new Computer(intel_cpu_ptr, intel_VideoCard_ptr, intel_Memory_ptr);
computer_ptr1->work();
delete computer_ptr1;
cout << "-------------------" << endl;
//第二台电脑组装(法二)
Computer *computer_ptr2 = new Computer(new lenovo_cpu, new lenovo_VideoCard, new lenovo_Memory);
computer_ptr2->work();
delete computer_ptr2;
cout << "-------------------" << endl;
//第三台电脑组装(法二)
Computer *computer_ptr3 = new Computer(new lenovo_cpu, new intel_VideoCard, new intel_Memory);
computer_ptr3->work();
delete computer_ptr3;
}
c++系列(持续更新中ing):
c++(引用、函数)
c++(类和对象_封装)
c++(类和对象_继承 / 多态)