【问题标题】:Virtual Functions in C++ and JavaC++ 和 Java 中的虚函数
【发布时间】:2012-10-12 22:44:11
【问题描述】:

我一直在阅读有关虚函数的内容并发现,

VF 用于继承类的多态性。

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

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

在 Java 中默认情况下:所有函数都是虚拟 C++:非虚拟,可以在 Java 中通过使用 final、private 访问修饰符将其变为虚拟,而在 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

这当然是对的。所以我的问题是输出完全违反了声明如果有问题的函数在基类中被指定为虚拟,那么派生类的函数将被调用。如果它不是虚拟的,则会调用基类的函数。对于调用:

  d1.function2();    

【问题讨论】:

  • 您从维基百科引用的那句话需要编辑或删除。
  • 哇..你怎么知道它来自维基百科..无论如何..感谢您消除疑问..我不应该依赖维基百科..
  • “并且可以通过使用 final、private 访问修饰符在 Java 中变为虚拟”没有任何意义。如果有人提供维基百科链接,我会修复它。
  • 其实我修复了this Wiki page,欢迎这里或那里的cmets,但它不包含我上面引用的文字,仍然欢迎指点。
  • @EJP 谢谢你,先生.. 你让世界变得更美好:)

标签: java c++ virtual-functions


【解决方案1】:

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

以你为例:-

#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

【讨论】:

    【解决方案2】:

    现在,您正在为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();
    

    【讨论】:

    • @FredLarson:是的——正如你评论的那样,正在编辑(还有更多)。不过还是谢谢。
    【解决方案3】:

    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()

    【讨论】:

      猜你喜欢
      • 2010-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-23
      相关资源
      最近更新 更多