本文共 3399 字,大约阅读时间需要 11 分钟。
多态指的是同一个行为,有不同的表现形式,在c++中,要实现多态的函数,必须在其函数前面加上virtual函数,否则,起不到多态作用。
不加virtual关键字的后果:
#includeusing namespace std;class Parent{public: Parent(int a) { this->a = a; cout << "Parent a" << a << endl; } void print() //子类的和父类的函数名字一样 { cout << "Parent 打印 a:" << a << endl; }protected:private: int a;};class Child : public Parent{public: Child(int b) : Parent(10) //父类的构造函数中有参数,因此在子类的构造函数中,要进行参数初始化列表 { this->b = b; cout << "Child b" << b << endl; } void print() { cout << "Child 打印 b:" << b << endl; }protected:private: int b;};void main(){ Parent* base = NULL; Parent p1(20); Child c1(30); base = &p1; base->print(); //执行父类的打印函数 base = &c1; base->print(); //在这里执行的也是父类的打印函数,因为重写的那个函数都没有加virtual关键字 cout << "hello..." << endl; system("pause"); return;}/**输出:Parent a20Parent a10Child b30Parent 打印 a:20Parent 打印 a:10*/
分析:在上面的代码中,重写的函数print没有加上virtual关键字,然后在main中用parent指针接收的时候,哪怕让它指向一个子类的类型,调用的结果也是父类的print函数,这是因为,这在c++中是静态联编的(没有加virtual关建字的时候),根据指针的类型从而就决定其指向什么类型。(C/C++是静态编译型语言,在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象,在编译此函数的时,编译器不可能知道指针 p 究竟指向了什么。编译器没有理由报错。于是,编译器认为最安全的做法是编译到父类的print函数,因为父类和子类肯定都有相同的print函数。)
但是在加了virtual关键字之后,多态的作用就体现出来,具体代码如下,注意看代码注释:
#includeusing namespace std;class Parent{public: Parent(int a) { this->a = a; cout << "Parent a" << a << endl; } virtual void print() //子类的和父类的函数名字一样 { cout << "Parent 打印 a:" << a << endl; }protected:private: int a;};class Child : public Parent{public: Child(int b) : Parent(10) //父类的构造函数中有参数,因此在子类的构造函数中,要进行参数初始化列表 { this->b = b; cout << "Child b" << b << endl; } virtual void print() { cout << "Child 打印 b:" << b << endl; }protected:private: int b;};void main(){ Parent* base = NULL; Parent p1(20); Child c1(30); base = &p1; base->print(); //执行父类的打印函数 base = &c1; base->print(); //执行子类的print函数,多态的作用就会体现出来 cout << "hello..." << endl; system("pause"); return;}/**输出:Parent a20Parent a10Child b30Parent 打印 a:20Child 打印 b:30*/
再看另外一个多态的例子:
#includeusing namespace std;//HeroFighter AdvHeroFighter EnemyFighterclass HeroFighter{public: virtual int power() //C++会对这个函数特殊处理 { return 10; }};class EnemyFighter{public: int attack() { return 15; }};class AdvHeroFighter : public HeroFighter{public: virtual int power() { return 20; }};class AdvAdvHeroFighter : public HeroFighter{public: virtual int power() { return 30; }};//多态威力//1 PlayObj给对象搭建舞台 看成一个框架//15:20void PlayObj(HeroFighter *hf, EnemyFighter *ef){ //不写virtual关键字 是静态联编 C++编译器根据HeroFighter类型,去执行 这个类型的power函数 在编译器编译阶段就已经决定了函数的调用 //动态联编: 迟绑定: //在运行的时候,根据具体对象(具体的类型),执行不同对象的函数 ,表现成多态. if (hf->power() > ef->attack()) //hf->power()函数调用会有多态发生 { printf("主角win\n"); } else { printf("主角挂掉\n"); }}//多态的思想//面向对象3大概念//封装: 突破c函数的概念....用类做函数参数的时候,可以使用对象的属性 和对象的方法 //继承: A B 代码复用//多态 : 可以使用未来...//多态很重要//实现多态的三个条件//C语言 间接赋值 是指针存在的最大意义//是c语言的特有的现象 (1 定义两个变量 2 建立关联 3 *p在被调用函数中去间接的修改实参的值)//实现多态的三个条件//1 要有继承 //2 要有虚函数重写//3 用父类指针(父类引用)指向子类对象....void main(){ HeroFighter hf; AdvHeroFighter Advhf; EnemyFighter ef; AdvAdvHeroFighter advadvhf; PlayObj(&hf, &ef); PlayObj(&Advhf, &ef); PlayObj(&advadvhf, &ef) ; //这个框架 能把我们后来人写的代码,给调用起来 cout<<"hello..."< ef.attack()) { printf("主角win\n"); } else { printf("主角挂掉\n"); } if (Advhf.power() > ef.attack()) { printf("Adv 主角win\n"); } else { printf("Adv 主角挂掉\n"); } cout<<"hello..."<
总结:
多态可以面向未来(只要接口跟以前相同,多态封装成框架之后,可以调用未来的代码),实现多态的3个要求:
(1) 要有继承
(2) 要有虚函数重载
(3) 要有父类的指针或者引入指向子类对象
转载地址:http://srzmi.baihongyu.com/