huangfu Blog
Love Leanote!
Toggle navigation
huangfu Blog
主页
About Me
归档
标签
12多态/类型识别(dynamic_cast 和 typeid)
2017-02-21 22:33:01
380
0
0
tarena
#多态 ##概念 当`父类型的指针或引用指向子类对象`时,通过父类型的指针或引用调用`虚函数`,如果`子类重写了这个虚函数`,则调用的`表现是子类`的,`否则是父类的`. * `继承`是构成多态的`基础` * `虚函数`是构成多态的`关键` * `函数重写`是多态的必备`条件` ##举例 #include <iostream> using namespace std; class Animal { public: void show() { cout << "Animal show" << endl; } /* 虚函数是构成多肽的关键*/ virtual void run() { cout << "Animal run" << endl; } virtual void fun() { cout << "Animal fun()" << endl; } }; /* 继承是多肽的基础*/ class Cat:public Animal { public: void show() { cout << "Cat show" << endl; } /* 需然省略了关键值,但他还是虚函数*/ void run() { cout << "Cat run" << endl; } void fun() { cout << "Cat fun()" << endl; } }; int main() { Cat cat; Animal* p1 = new Cat(); p1->show(); // Animal show p1->run(); // Cat run p1->fun(); // Cat fun Animal* p2 = &cat; // 满足多态的条件 Animal& p3 = cat; // 满足多态的条件 Animal p4 = cat; // 不满足多态的条件 } ##多态的应用 (类型更加通用,根据具体的对象做出具体的行为) * 用在函数的参数上 void testAnimal(Animal* p) * 用在函数的返回值上 Animal* getAnimal(int s); ##动态绑定 `静态绑定`:在编译时就直接确定调用的函数地址 `动态绑定`:在运行时确定函数的调用地址 ##多态的底层实现 虚函数表 ----> 虚表 虚指针 任何一个具有虚函数的类型,只有一张虚表,同类型的对象共享虚函数表. `多肽原理图:` ![](https://leanote.com/api/file/getImage?fileId=59ca001fab64417152001dae) #类型识别 ##为什么要有类型识别??? 多肽做到的效果是类型的通用,但这样损失了对象的个性 有时候要恢复个性,根据具体的类型做出相应的个性展现 ##举例 #include <iostream> using namespace std; class Animal { public: virtual void run() { cout << "Animal run()" << endl; } }; class Cat { public: void run() { cout << "Cat run()" << endl; } void show() { cout << "Cat show()" << endl; } }; int main() { Cat cat; Anima* p = &cat; p->run(); // 调用正常 p->show(); // 编译出错 /* 使用dynamic_cast做类型转换*/ Cat* pcat = dynamic_cast<Cat*>(p); pcat->show(); // 调用正常 /* 注意不能使用C语言强制类型转换,编译有可能不会报错误,如果没有设计到内存,运行也有可能没问题*/ /* 但是,一旦涉及到内存,则程序会段错误*/ } ##使用dynamic_cast<类型>(对象) 它尝试着把对象变成相应的类型,如果成功返回非空指针,不成功返回NULL 注意dynamic_cast`只适用于父子类的多肽类之间` /* 在开发中dynamic_cast的用法*/ if(dynamic_cast<Dog*>(p)) { ((Dog*)p)->dogShow(); } if(dynamic_cast<Cat*>(p)) { ((Cat*)p)->catShow(); } ##使用typeid运算符做类型识别 这个运算符可以获得类型或对象的类型信息 使用typeid要包含/usr/include/c++/4.x 下的`<typeinfo>`这个头文件 #include <typeinfo> typeid返回的信息存入一个type_info类型对象中,这个类型重载了 == 和 != 运算符 并且有个成员函数name()返回类型的名称 如果父子类之间没有多肽性,则当父类对象指针,指针指向子类对象时,通过解引用地址后做typeid运算识别出的对象是父类型的,如果有多肽性,则它可以识别出子类对象. 所以无论使用dynamic_cast还是使用typeid都要求有多肽性. ###typeid用于普通类型 #include <iostream> #include <typeinfo> using namespace std; int main() { /* typeid用于普通类型变量*/ int i; cout << typeid(i).name() << endl; // i cout << typeid(int).name() << endl; // i /* typeid用于指针类型*/ int* pi; cout << typeid(pi).name() << endl; // Pi cout << typeid(int*).name() << endl; // Pi /* typeid用于解引用后的指针*/ cout << typeid(*pi).name() << endl; // i } ###typeid用于没有多肽的父子类类型 #include <typeinfo> #include <iostream> using namespace std; class Animal { }; class Dog:public Animal { }; int main() { /* typeid用于普通类类型*/ Dog dog; cout << typeid(dog).name() << endl; // 3Dog /* typeid用于指向类的指针类型*/ Animal* a; cout << typeid(a).name() << endl; // P6Animal cout << typeid(*a).name() << endl; // 6Animal /* typeid用于父类指针指向子类对象,并无多肽性的父子类之间*/ a = &dog; cout << typeid(a).name() << endl; // P6Animal cout << typeid(*a).name() << endl; // 6Animal 没有判别处Dog的类型 } ###typeid用于具有多态性的父子类之间 #include <typeinfo> #include <iostream> using namespace std; class Animal { public: virtual void show() { } }; class Dog:public Animal { public: void show() { } }; int main() { /* typeid用于具有多肽性的父子类之间*/ Dog dog; Animal* p = &dog; cout << typeid(p).name() << endl; // P6Animal cout << typeid(*p).name() << endl; // 3Dog 识别正确 /* typeid在开发中的应用*/ if(typeid(*p) == typeid(Dog)) { // ... ... } /* typeid运算结果存储在type_info类型中,并且这个类型重载了== 和 != 运算符*/ }
上一篇:
13简化指针/抽象类/虚析构
下一篇:
11多继承/虚继承/虚函数/函数重写(覆盖)
0
赞
380 人读过
新浪微博
微信
腾讯微博
QQ空间
人人网
提交评论
立即登录
, 发表评论.
没有帐号?
立即注册
0
条评论
More...
文档导航
没有帐号? 立即注册