4

我一直在阅读有关虚拟功能的信息并发现,

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

3 回答 3

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
于 2012-10-23T03:34:54.490 回答
4

现在,您正在为每个baseand创建一个对象derived,然后直接在这些对象上调用function1and 。function2在这些条件下,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当您调用 each 的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();
于 2012-10-23T03:19:34.343 回答
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()

于 2012-10-23T03:17:31.900 回答