虚函数的作用
/*******以virtual关键字声明的函数就为虚函数么?********//***************虚函数是否类似重载?*******************/class Eax{protected: double price;public: virtual void a(): price(0.0){}};class Ebx: public Eax{public: void a(double &d){price(d);}};/***virtual又有什么作用?虚函数又有什么作用?一般定义派生类是否要定义虚函数?***/
struct B{ virtual void fun() { printf("B.fun\r\n"); } void do_fun() { printf("B.do_fun\r\n"); }};struct D : public B{ virtual void fun() { printf("D.fun\r\n"); } void do_fun() { printf("D.do_fun\r\n"); }};int _tmain(int argc, _TCHAR* argv[]){ B* pd = new D; pd->do_fun(); // 输出 B.do_fun pd->fun(); // 输出 D.fun return 0;}
[解决办法]
/*******以virtual关键字声明的函数就为虚函数么?********/ //是/***************虚函数是否类似重载?*******************/ //虚函数和重载是C++实现多态的两种方式class Eax{protected: double price;public: virtual void a(): price(0.0){} //虚函数和内联冲突,虚函数优先级要高,所以为虚函数。};class Ebx: public Eax{public: void a(double &d){price(d);} //不是虚函数,请百度 遮盖(覆盖)};/***virtual又有什么作用?虚函数又有什么作用?一般定义派生类是否要定义虚函数?***/// virtual 用来声明虚函数。// 虚函数用来实现动态多态(又叫运行时多态),相应的重载用来实现静态多态的一种方式。// 看需求
[解决办法]
虚函数是实现多态的 也可以说是判断
[解决办法]
首先虚函数是用在有继承关系的父类中。虚函数是通过动态编译实现的,编译器在编译时并不知道编译时函数是属于哪个类(是父类还是子类)对象的。 只有在执行时才能决定到底是哪个类型的对象调用这个函数。
而函数重载应该是在同一作用域中,函数名相同,但是参数个数不同,或是参数类型不同,或是返回值类型不同,这种的情况才叫函数重载。 我想你应该想说的是重定义, 那样的话就是你对象是什么类型,就调用类中对应的函数。
只有virtual 关键字,这个函数才是虚函数。
对于虚函数,你应该看C++primer,你要明白什么是虚指针,虚函数表。 理解了,你就应该知道虚函数的作用了。
看effective C++ 里的条款36:区分接口继承和实现继承, 你大概就知道什么时候应该声明virtual,为什么要声明virtual。
[解决办法]
大哥,上面的说法有点误会吧,函数重载只有两种情况耶:函数参数个数不同,函数类型不同,函数的返回值类型不同不能构成函数重载,因为编译器在确定调用哪个函数是从实参和形参的对应来调用的,也就是说即使形参个数和类型相同但是返回值不同不能构成重载,会调用错误
[解决办法]
敢问LZ看的是什么书??
想知道相应层次的东西,就该看对应的书。最好各个层次的书都有一两本,这样对照着看,效果才会好
其实你喜欢问的态度没什么,但是,光这样问的话,并不是最好的学习方法
跟我学C++之掌握C++在学习MFC之前,我们有必要对C++中面向对象的一些特性进行加深了解和掌握。下面就和我一起来掌握C++1.C++对于字符串的处理 C语言和C++对于字符都是用char型变量来实现的,但是对于字符串的处理上,C++明显要强大得多。 我们知道C语言对于字符串的处理是用char*,对应的头文件为string.h。C++中保留了这种C风格的处理方式,但是,其头文件变为了cstring.h。前面的c表示了这是C语言的东西。而C++的string.h头文件定义了C++自己的字符串解决方案:string类。而在MFC中,微软又封装了一个更强大的字符串类:CString。当然,MFC不是标准C++的内容。2.结构体和类 C语言是面向过程的,而C++主要是面向对象的。这之中,最大的区别就是C++中引入了类的概念。而且,C++扩展了结构体的功能,C语言中,结构体中不能有函数,而C++的结构体可以有函数。 C++中结构体是一种精简版的“类”,其和类的主要区别主要表现在构造函数和析构函数方面。 我们国内很多介绍C++的图书,包括我在大一时学习C++的教材对于构造函数的作用,要么是错误的,要么是不清楚的。下面给出的是ANSI C++的ISO标准中对于构造函数的说明: 如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认的构造函数: A、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时; B、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数); C、在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)。 3.this指针 在Java中,this代表是一个对象,调用方式为 “this.”,而在C++中,this是一个对象指针,调用方式为“this->”。 this指针 this指针是一个隐含的指针,它是指向对象本身,代表了对象的地址 一个类所有的对象调用的成员函数都是同一代码段。那么成员函数又是怎么识别属于同一对象的数据成员呢。原来,在对象调用比如pt.output(10,10)时,成员函数除了接受2个实参外,还接受到了一个对象pt的地址。这个地址被一个隐含的形参this指针所获取,它等同于执行this=&pt。所有对数据成员的访问都隐含地被加上前缀this->。例如:x=0; 等价于 this->x=0。 4.类的继承和派生 在C++中,给我们提供了一种重要的机制,就是继承。理解继承是理解面向对象程序设计的关键。 在C++中,类的继续是原汁原味的,因为它支持多继承,而JAVA处理不好多继承,只能不允许多继承,并在不得不多继承时引入接口的概念。而接口相当于C++中抽象类和纯虚函数的精简版。 JAVA没有纯虚函数,只有虚函数,有虚函数的类叫抽象类,并且虚函数没有方法体。 C++中有虚函数,也有纯虚函数。两者都是可以有方法体,一般不对纯虚函数不写方法体。有虚函数的类不是抽象类,可以实例化对象。有纯虚函数的类才叫抽象类。5.多态性 面向对象语言的三大特性中,封装性和继承性比较统一,但是多态性各有不同。下面以C++和JAVA的对比来说明。 因为JAVA没有指针,所以比较简单,先说JAVA。JAVA的多态性分为静态多态性和动态多态性。 JAVA的静态多态性是指类内方法的重载,这一点和C++相同。但是C++中重载就是重载,没有静态多态性这个说法。 JAVA的动态多态性就是子类与父类间同名方法的动态选择。而在C++中,动态选择更加复杂,分为了函数的覆盖和隐藏两个内容。 下面讲C++。先说C++中同名函数的三种关系:重载,覆盖,隐藏(这在JAVA里面是没有的)。 1)重载的构成条件: A.函数必须是在一个域内,要么是全局的,要么是同一个类的成员函数,不能是派出类(子类)和基类(父类)间,更不能是两个类间的。 B.函数的名称必须相同。其参数类型,参数个数不能完全相同。 C.只有返回值不同不能构成重载。 2)覆盖的构成条件: A.函数必须是派出类(子类)和基类(父类)之间的。 B.基类函数必须是虚函数(使用virtual关键字进行声明)。 C.函数名称与参数列表必须完全相同。 注意:两个覆盖函数间,基类中的函数用virtual关键字声明,是虚函数。而派生类中的函数无论是否有virtual关键字声明,都是虚函数。 值得说明的是:C++的多态性就由虚函数,即函数的覆盖来实现的。 3)隐藏的构成条件: A.函数必须是派出类(子类)和基类(父类)之间的。 B.函数名称相同,参数列表可相同,可不同。 C.两个函数都不是虚函数。 重载比较好理解,覆盖和隐藏不易区分。下面,用一个例子来说明: #include <iostream> using namespace std; class Animal { public: Animal(int height, int weight) { } virtual void eat(int i) { cout<<"animal eat"<<endl; } void sleep(float i) { cout<<"animal sleep"<<endl; } void breathe(int i) { cout<<"aniaml breathe"<<endl; } }; class Fish : public Animal { public: Fish():Animal(300,400) { } void eat(int i) //函数覆盖 { cout<<"fish eat"<<endl; } void sleep(int i) //函数隐藏 形参不同 { cout<<"fish sleep"<<endl; } void breathe(int i) //函数隐藏 形参相同 { cout<<"fish bubble"<<endl; } }; int main(int argc, char* argv[]) { Fish fh; Animal *pa=&fh; Fish *pf=&fh; pa->eat(1); //函数覆盖实现了C++的多态性 pf->eat(1); cout<<"-----------------------"<<endl; pa->sleep(1); //函数隐藏不能实现C++的多态性 pf->sleep(1); cout<<"-----------------------"<<endl; pa->breathe(1); //函数隐藏不能实现C++的多态性 pf->breathe(1); return 0; } 读者可以想像一下运行结果: eat函数是函数覆盖,则能分辨两个指针原来都是Fish类的fh对象的,因此输出的都是“fish eat” sleep函数和breathe函数是函数隐藏,已经不能分辨两个指针的真实来源,“误”以为是一个是Animal的,一个是Fish的,则输出的结果为: animal sleep fish sleep aniaml breathe fish bubble 读者可以发现,多态性指的是派出类(子类)和基类(父类)经过强制类型转换后还能分辨原来类型的能力。而且这里只针对对象指针,对象不行。 如果没有经过强制类型转换,当然结果都是各自调用各自的类的。 比如在main函数中的如下调用: Fish f; Animal a=f; a.eat(1); //虽然a是由f而来,但不是指针,不能多态,不能分辨原来的类型,结果是animal eat f.eat(1); //结果是fish eat cout<<"-----------------------"<<endl; a.sleep(1); //animal sleep f.sleep(1); //fish sleep cout<<"-----------------------"<<endl; a.breathe(1); //aniaml breathe f.breathe(1); //fish bubble cout<<"======================"<<endl; Animal animal(1, 1); Animal *pa2=&animal; Fish fish; Fish *pf2=&fish; pa2->eat(1); //结果是animal eat pf2->eat(1); //结果是fish eat cout<<"-----------------------"<<endl; pa2->sleep(1); //结果是animal sleep pf2->sleep(1); //结果是fish sleep cout<<"-----------------------"<<endl; pa2->breathe(1); //结果是aniaml breathe pf2->breathe(1); //结果是fish bubble cout<<"======================"<<endl; Fish f2; Animal a2(1, 1); a2.eat(1); //结果是animal eat f2.eat(1); //结果是fish eat cout<<"-----------------------"<<endl; a2.sleep(1); //结果是animal sleep f2.sleep(1); //结果是fish sleep cout<<"-----------------------"<<endl; a2.breathe(1); //结果是aniaml breathe f2.breathe(1); //结果是fish bubble6.其他一些重点 1)命名空间。C++支持自定义命名空间。这是高级用法。 2)泛型。C++有着极强的泛型支持,比JAVA要强很多。这是高级用法。 3)main函数。标准C++里面,main函数的写法是有规定的,只能是: int main(int argc, char* argv[]) 本文完。附:多态性中的代码和运行结果:#include <iostream>using namespace std;class Animal{public: Animal(int height, int weight) { } virtual void eat(int i) { cout<<"animal eat"<<endl; } void sleep(float i) { cout<<"animal sleep"<<endl; } void breathe(int i) { cout<<"aniaml breathe"<<endl; }};class Fish : public Animal{public: Fish():Animal(300,400) { } void eat(int i) //函数覆盖 { cout<<"fish eat"<<endl; } void sleep(int i) //函数隐藏 形参不同 { cout<<"fish sleep"<<endl; } void breathe(int i) //函数隐藏 形参相同 { cout<<"fish bubble"<<endl; }};int main(int argc, char* argv[]) { Fish fh; Animal *pa=&fh; Fish *pf=&fh; pa->eat(1); //函数覆盖实现了C++的多态性 pf->eat(1); cout<<"-----------------------"<<endl; pa->sleep(1); //函数隐藏不能实现C++的多态性 pf->sleep(1); cout<<"-----------------------"<<endl; pa->breathe(1); //函数隐藏不能实现C++的多态性 pf->breathe(1); cout<<"======================"<<endl; Fish f; Animal a=f; a.eat(1); f.eat(1); cout<<"-----------------------"<<endl; a.sleep(1); f.sleep(1); cout<<"-----------------------"<<endl; a.breathe(1); f.breathe(1); cout<<"======================"<<endl; Animal animal(1, 1); Animal *pa2=&animal; Fish fish; Fish *pf2=&fish; pa2->eat(1); pf2->eat(1); cout<<"-----------------------"<<endl; pa2->sleep(1); pf2->sleep(1); cout<<"-----------------------"<<endl; pa2->breathe(1); pf2->breathe(1); cout<<"======================"<<endl; Fish f2; Animal a2(1, 1); a2.eat(1); f2.eat(1); cout<<"-----------------------"<<endl; a2.sleep(1); f2.sleep(1); cout<<"-----------------------"<<endl; a2.breathe(1); f2.breathe(1); return 0;}//运行结果:/*fish eatfish eat-----------------------animal sleepfish sleep-----------------------aniaml breathefish bubble======================animal eatfish eat-----------------------animal sleepfish sleep-----------------------aniaml breathefish bubble======================animal eatfish eat-----------------------animal sleepfish sleep-----------------------aniaml breathefish bubble======================animal eatfish eat-----------------------animal sleepfish sleep-----------------------aniaml breathefish bubble*/