c++(类和对象_继承 / 多态)

继承

基本语法

  • 好处:减少重复代码
  • 公式:class A :public B {...}
  • A类称为子类、派生类
    • 包括两大部分:
      1. 从基类继承过来的
      2. 子类自己添加的内容
  • 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 {...}
  • 继承方式:
    1. public:公共继承
    2. protected:保护继承
    3. 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
    在这里插入图片描述


多态

概念

  • 两类
    1. 静态多态:函数重载、运算符重载,复用函数名 —>函数地址早绑定(编译阶段)
    2. 动态多态:派生类、虚函数、纯虚函数,实现运行时多态 —>函数地址晚绑定(运行阶段)

动态多态满足条件:有继承关系子类重写父类的虚函数

  • 重写:函数返回类型、函数名、参数列表 完全一致

使用:父类的指针或引用指向子类对象

#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 = &square;
    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++(类和对象_继承 / 多态)









  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值