读书人

虚函数的作用,该怎么解决

发布时间: 2012-04-30 22:33:26 作者: rapoo

虚函数的作用

C/C++ code
/*******以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又有什么作用?虚函数又有什么作用?一般定义派生类是否要定义虚函数?***/


[解决办法]
http://topic.csdn.net/u/20100805/09/18b3c8c1-6561-4996-a1ce-009d4cec5791.html
[解决办法]
我感觉虚函数主要是用来实现多态的,楼主请参考玄机逸士的博客:
http://patmusing.blog.163.com/blog/static/135834960201111244821914/
[解决办法]
多态性:

当基类和派生类的某一个函数所实现的功能不同(函数被重载)时,不需要知道当前使用的是基类还是任何一个派生类,即可以根据实际类型执行所需的功能

C++实现:

一个指向基类类型的指针既可以指向基类对象,也可以用来指向派生类对象
但使用这个指针调用成员函数的时候,会直接根据指针自身的类型调用基类的成员函数——哪怕这个指针实际上指向一个派生类对象并且重载了此成员函数
但如果声明该成员函数为虚函数,那么使用指针调用该成员函数的时候,就会根据指针指向对象的实际类型调用该类型所重载的成员函数
[解决办法]
估计lz没写过比较多一点的代码,类应该都是数据封装而没涉及到继承。
等见过一些框架,看过一些代码自然了解有什么好处。
[解决办法]
虚函数是用来实现多态性的。
当派生类与基类中有两个的成员函数时,而且在调用这个同名的成员函数时,想要使用派生类的方法,而不是
基类中的方法,那么就可以定义成虚函数,然后在派生类中要重新定义这个方法。由于虚函数会被继承,所以
在派生类中不用再添上virtual,就算添上也没有事,也会被忽略掉。
[解决办法]
看看书去吧。关于C++虚函数的。
[解决办法]
说实话,我觉得学东西的时候就问“这东西有什么用”的,十有八九都是学不好的

也许是无理的个人偏见吧
[解决办法]
用来复用代码的

这个东西等到接触了一些类库的设计就明白作用了

MFC的消息映射实现的功能也就是虚函数的功能
[解决办法]
LZ问的东西,基本上,1楼的帖子里面都有答案了的...
贴一个比较容易理解的回答...
虚函数是为了实现多态。当父类被子类继承后,父类中的某些函数在子类中要重新定义,则声明其为虚函数。例如:
class A
{
.......
virtual int fun(int a ,char *b); //实现A功能
.......
};

class B: public A
{
........
int fun(int a, char *b); //实现B功能
........
};

A *objA = new(B);
objA.fun(); //这里调用的是:B::fun(int a, char *b),实现的是B功能

[解决办法]
c++的多态就靠虚函数撑着呢。。
[解决办法]
多态。。。。。。
[解决办法]
*******以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 void a(): price(1.0){}
};

/***virtual又有什么作用?虚函数又有什么作用?一般定义派生类是否要定义虚函数?***/
虚函数的形参返回值啥的必须和基类中virtual声明的那个一样一样的才可以的,函数体里面内容可以不同,用来实现多态。
你那个void a(double &d){price(d);}
不叫虚函数,是另外一个重载了吧?
[解决办法]
错了,派生类中没有virtual关键字。
[解决办法]
effective c++中有你的答案,虚函数有什么用
[解决办法]
虚函数体现C++中的很重要的特性——多态
将派生类的对象赋给基类的指针或引用,通过基类可以访问派生类的继承基类的虚成员函数
------解决方案--------------------


长的一模一样并且virtual叫虚函数。

另外,重载必须发生在相同的作用域内,基类和派生类不是一个作用域。
再另外,楼主的代码是典型的同名覆盖,因为参数不同,不形成多态,也不形成重载(除非你在派生类再写一个a函数,形参不同)。
[解决办法]
提供途径让父类既能调用到子类的代码,又不需要修改父类自身,原则上也不需要关心子类代码的实现细节。
[解决办法]
virtual 是将此函数声明为虚函数的关键字。
虚函数使得子类调用父类方法时,能够定位到自己的方法上。比如:

C/C++ code
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关键字。

[解决办法]
具有virtual函数的类,是要当父亲,它的孩子们根据自己的需求来完成virtual函数的具体功能实现。
virtual函数是多态的根基。
[解决办法]
你写这个虚函数没用。子类参数都变了
[解决办法]
C/C++ code
/*******以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++虚函数的。
说实话,我不太喜欢你这么说法...我难道没看书么?如果看明白了我还上来问什么?

[解决办法]
这是我看了VC++深入详解后写的笔记,拿出来分享

虚函数的作用和其与重载的关系一目了然
[size=16px][/size]

C/C++ code
跟我学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*/ 

读书人网 >C++

热点推荐