C ++和Java中的虚函数

时间:2012-10-23 03:11:00

标签: java c++ virtual-functions

我一直在阅读有关虚拟功能的内容并找到了,

VF用于继承类的多态性。

因此,如果类和派生类都具有相同的函数名,则VF会将相应的函数绑定到函数调用。

即。如果有问题的函数在基类中被指定为virtual,则将调用派生类的函数。如果它不是虚拟的,则会调用基类的函数。

默认情况下在Java中:所有函数都是Virtual C ++:非虚拟,可以使用final,private访问修饰符在Java中使用Virtual,而在C ++中使用Virtual关键字将函数设置为虚拟。

基于上述理论,我编写了代码:

#include <iostream>

class base{
    public : 
        virtual void function1(){
            std::cout<<"BaseVirtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Base NonVirtual"<<std::endl;
        }
};


class derieved: public base
{
    public : 
        void function1(){
            std::cout<<"Derieved Virtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Derieved NonVirtual"<<std::endl;
        }
};



int main()
{
    base b1;
    derieved d1;

    b1.function1();
    b1.function2();

    d1.function1();
    d1.function2();    

}

现在基于这样的事实,如果它是一个虚函数,那么只调用派生类函数,我上面程序的输出应该是:

BaseVirtual
Base NonVirtual
Derieved Virtual
Base NonVirtual
然而,它出现了:

BaseVirtual
Base NonVirtual
Derieved Virtual
Derieved NonVirtual

当然必须是正确的。所以我的问题是输出完全违反了语句如果有问题的函数在基类中被指定为virtual,那么将调用派生类的函数。如果它不是虚拟的,则调用基类的函数。

  d1.function2();    

3 个答案:

答案 0 :(得分:9)

是..当且仅当您尝试使用基类指针访问派生类对象时,虚拟的角色才会出现。

以你为例: -

#include <iostream>

class base{
    public : 
        virtual void function1(){
            std::cout<<"BaseVirtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Base NonVirtual"<<std::endl;
        }
};


class derieved: public base
{
    public : 
        void function1(){
            std::cout<<"Derieved Virtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Derieved NonVirtual"<<std::endl;
        }
};



int main()
{
    base *b1;
    derieved d1;

    b1=&d1;

    b1->function1();
    b1->function2();    
    return 0;
}

输出: -

Derieved Virtual
Base NonVirtual

答案 1 :(得分:4)

现在,您要创建一个basederived对象,然后直接在这些对象上调用function1function2。在这些条件下,virtual(或缺少)根本没有任何区别。

至少在C ++中,virtual表示任何内容,您需要使用指向基类的指针(或引用),该基类引用可能是基类或派生类的对象:

base *b2 = &d1;

// invoke non-virtual function. Inovkes base::function1, because we're using 
// pointer to base.
b2->function1(); 

// invoke virtual function. Invokes derived::function2 because the pointee object
// is a derived.
b2->function2();

如果你有(例如)一个指向对象的指针集合,那么这一点特别有用,那些指针引用的对象可能是几种不同类型中的任何一种。其中一个经典示例是基础shape类,其中包含linecirclesquare等。当您调用每个draw成员时,每个成员都会绘制自己的形状。在这种特殊情况下,您的基类可能是一个抽象基类 - draw成员被声明为“纯虚拟”,这意味着您无法创建基类shape类的对象,并且创建派生类的实例,必须覆盖draw成员函数:

class shape {
public:
    virtual void draw() = 0;
};

class circle : public shape { 
public:
    virtual void draw() { /* draw itself */ }
};

然后,在你的绘图程序中,你有一个(指针)用户创建的形状的集合,并将它们全部绘制出来,你只需遍历集合并告诉每个人绘制自己。更高级别的代码不需要知道或关心特定形状是圆形,方形,三角形等。

for (int i=0; i<shapes.size(); i++)
    shapes[i]->draw();

答案 2 :(得分:1)

C ++中的多态性需要利用指针。如果您将示例更改为:

base *b1 = new base();
base *d1 = new derived();

这实际上将利用虚拟机制。但是,您似乎与多态性背后的基本思想相混淆。如果将类定义为派生类,当然它将调用derived类中定义的函数,同样调用base

编辑:为了使其更加明确,这里是输出和解释:

b1->function1(); //Will call base::function1()
b1->function2(); //Will call base::function2()
d1->function1(); //Will call derived::function1()
d2->function2(); //Will call derived::function2()

所有多态/虚拟调用都允许您将派生指针视为基类型,同时在其上调用(正确的)派生函数。所以,如果你有另一个功能,如:

void foo(base& b)
{
    b.function1();
}

然后传递b1将致电base::function1(),通过d1会致电derived::function1()