一:胡聊时间
寒假也结束了,这几天没写博客,是因为玩了胡闹厨房,有一说一挺有趣的,如果你有朋友的话。胡说八道时间就结束吧,今天就拿胡闹厨房的菜来举例多态吧,来模拟一下游戏菜的各种状态、
二:多态、
概念,我不是很喜欢这种条条框框的东西,大抵就是完成某一个行为时,不同的对象会有不同的状态。
常规多态(类型无关)
我们拿胡闹厨房举例的话,食物都会有做好,糊了等等几个状态对么?我们设置Food基类用虚函数写一个糊掉了的函数,在子类继承后可以重写Flop函数,也就是所谓的多态,这个是常规的多态.
#include<iostream>
class Food
public:
virtual void Flop() const
std::cout << "食物糊了" <<std:: endl;
class Fish:public Food
public:
void Flop() const override
std::cout << "鱼肉糊了" << std::endl;
class Hamburg:public Food
public:
void Flop() const override
std::cout << "汉堡糊了" << std::endl;
void Print(const Food& food)
food.Flop();
int main()
Fish fish;
Hamburg burg;
Print(fish);
Print(burg);
从上面可以看出来,这种多态的本质就是与类型无关, 像鱼肉(class Fish)和汉堡(class Hamburg)都是继承于食物(class Food),所以在Print函数调用时我们可以把它们转成他们的基类Food进行调用,再调用Flop方法,就会调用子类重写的两个方法,从而实现了多态,所以说与类型无关的.实现多态虚函数只是一种方式,但这种方式是最常用且简单的,也方便扩展.
那我们不用继承可以写一个类似的与类型无关的多态么?我们将它换成枚举类型试试:
非继承多态
#include<iostream>
enum Food_Type
un_Set,Fish,Hamburg,
class Food
public:
Food(Food_Type food_type) :food_type(food_type) {}
void Flop() const
switch (food_type)
case un_Set:
std::cout << "un_Set" << std::endl;
break;
case Fish:
std::cout << "鱼肉糊了" << std::endl;
break;
case Hamburg:
std::cout << "汉堡糊了" << std::endl;
break;
default:
std::cout << "肖战糊了" << std::endl;
break;
private:
Food_Type food_type;
void Print(const Food& food)
food.Flop();
int main()
Food Fish(Food_Type::Fish);
Print(Fish);
我们通过这种方法也能实现多态,但这段代码明显没有面向对象极其难扩展,若加了两道菜不见要改枚举类型,也要在类内添加相应食物代码.这段代码是运行时的多态.
那我们是否可以不使用虚函数完成多态呢?
#include<iostream>
class Food
public:
void Flop() const
std::cout << "食物糊了" <<std:: endl;
class Fish:public Food
public:
void Flop() const
std::cout << "鱼肉糊了" << std::endl;
class Hamburg:public Food
public:
void Flop() const
std::cout << "汉堡糊了" << std::endl;
template<typename F_T>
void Print(const F_T &food)
food.Flop();
int main()
Fish fish;
Hamburg hamburg;
Print(fish);
Print(hamburg);
这里我们运用了函数模板的实参推导,英文叫做argument deduction这里我们不具体展开讲这个,使用这个方法后就可以实现一个简单的静态多态.
说到静态多态很多都会提到CRTP这个东西(Curiously Recurring Remplate Pattern)翻译过来叫一种奇特的模板方式.那么 CRTP有什么不同呢?
#include<iostream>
template<typename Derived>
class Food
public:
void Flop() const
static_cast<Derived*>(this)->Flop();
void PrintCount()
std::cout << FlopCount << std::endl;
protected:
static int FlopCount;
template<typename Derived> int Food<Derived>::FlopCount = 0;
class Fish:public Food<Fish>
public:
Fish()
FlopCount++;
void Flop() const
std::cout << "鱼肉糊了" << std::endl;
~Fish()
FlopCount--;
class Hamburg:public Food<Hamburg>
public:
Hamburg()
FlopCount++;
void Flop() const
std::cout << "汉堡糊了" << std::endl;
~Hamburg()
FlopCount--;
template<typename F_T>
void Print(const F_T& food)
food.Flop();
int main()
Fish fish1;
Fish fish2;
Hamburg hamburg;
fish1.PrintCount();
hamburg.PrintCount();
Print(fish1);
Print(hamburg);
看起来和之前代码变化不大是么,这里多添加了个糊掉的数量方便我们理解,这里表面上我们的Fish和Hambuger共用同一个基类,但实际上他们是两个不同的类,Fish继承了Food<Fish>这个类,Hambuger继承了Food<Hambuger>这个类,是两个不同的类,我们可以通过FlopCount验证.
可以看到fish打印出是2,hamburg打印出是1,所以实际上他们不是用共同的一个基类.以上就是CRTP的方法,没有用到虚函数虚表就实现了多态,好消息是节省了一些开销,但如果想把他们加入到同一个容器里,不免的还是需要用到虚函数虚表.
以上就是简单介绍了下C++实现多态的几种方法,希望大家看后不要还是别人一问,C++多态是什么,就说虚函数虚表,哈哈哈,还有CRTP,静态多态,非继承多态等等.还有一个问题,胡闹厨房4颗星是真的有正常人能打出来么,我觉得吧有点不可能.
一切为KNGG一名普通大学生编写,希望有疑惑不对的地方还是欢迎您指正!!!!!!!!!!!
多态就是多种形态,C++的多态分为静态多态与动态多态。
静态多态就是编译器根据函数实参的类型判断出要调用哪个函数。比如函数重载和函数模板。
动态多态依靠的是虚函数表和动态绑定机制,因为是在运行时根据对象的类型在虚函数表中寻找调用函数的地址来调用相应的函数,所以称为动态多态。
面向对象的三个特征:封装、继承和多态。
什么是多态
多态的意思是一个事物有多种形态,英文单词为polymorphism,向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(方法)。也就是说,每个对象可以用自己的方式去相应共同的消息。
例如函数的重载、运算符的重载都是多态现象。
一个生活中的例子,比如学生开学,校长发布一条哪一天开学的信息,不同的对象会产生不同的反应,学生就要准备上学,家...
今天来聊聊
C++ Eigen 中的一个技巧——奇异递归模板模式(curiously recurring
template pattern),简写为CRTP。
这篇博客也是我边看、边查、边理解的一个过程。如有错误,希望大神留言指正。
原来已经稍微接扫了几眼这个技术,在我粗浅的认识中,他在编译期通过模板,实现了大家用的比较多的运行时
多态。我们来看看这个代码:
class Base
说到面向对象特性之一“多态”,以我的水平已经说不出太多新意了。相信很多程序员代码K多了,做梦都在“多态中”运行着。常规的多态是C++语义内置支持的一种特性,通过虚函数可以实现这个特性,为了后面以示区别,我们姑且把这种多态称为“动态多态”或”运行期多态“,而本文总主要想讨论下“静态多态”,也可以叫“编译期多态”,同时一起来看下,静态多态会给我们带来哪些惊喜之处,拭目以待吧。
首先看个正常