什么是真正的虚拟功能?

时间:2012-02-19 11:22:08

标签: c++ function virtual

我想了解虚函数的用途。

让我们分析一下成员函数是非虚拟的代码:

示例1:

struct A
{ 
    void foo1() { cout << "foo 1 from A \n"; }
};

struct B : A
{
    void foo1() { cout << "foo 1 from B \n"; }
};

int main()
{
    A *a = new B;
    a->foo1(); // will print "foo 1 from A \n" because A::foo1 isn't virtual

    B *b = new B;
    b->foo1(); // will print "foo 1 from B \n"
}

我们看到a->foo1()的输出;将是“foo 1 from A”但我希望函数B执行自己的foo1函数。所以我必须覆盖它并使A::foo1虚函数。

示例2:

struct A
{ 
    virtual void foo1() { cout << "foo 1 from A \n"; }
};

struct B :  A
{
    void foo1() { cout << "foo 1 from B \n"; }
};

int main()
{
    A *a = new B;
    a->foo1(); // will print "foo 1 from B \n"

    B *b = new B;
    b->foo1(); // will print "foo 1 from B \n"
}

现在A::foo1已被覆盖,a->foo1()按照我们的要求打印“来自B的foo 1”。但是,让我们考虑一下B类具有A:

中不存在的某些功能的情况

示例3:

struct A
{ 
    int a;
    void foo1() { cout << "foo 1 from A \n"; }
};

struct B : A
{
    int b;
    void foo1() { cout << "foo 1 from B \n"; }
    void foo2() { cout << "foo 2 from B \n"; }
};

int main()
{
  A *a = new B;
  // a->foo2(); // compiler error, a doesn't see foo2 function
  a->foo1();
  // a->b = 1; // compiler error, a doesn't see member variable b
  a->a = 1;

  // We aren't going to do B *b = new A; here because that's nonsense
  B *b = new B;
  b->foo2(); // ok
  b->foo1(); // ok
  b->b = 1; // ok
  b->a = 1; // ok
}

正如我们现在看到的,B不是A的精确副本;它继承了A并用一些新函数和变量扩展它。我们无法a->foo2()a->b

我认为A *a = new B;这样的陈述在阅读或分析代码时要比B *b = new B;更加混乱。

我知道b是指向B实例的指针。想知道A*指向的对象类型是什么并不困惑吗?

所以我的问题是:我们可以使用虚拟函数吗?

如果基类中没有变量或函数,我不会将它用于派生类。使用B *b = new B;创建新对象更加清晰,而不是A *a = new B;

当我使用B *b = new B;创建B的实例时,A的成员函数不需要是虚拟的,因为B将使用自己的A::foo1自动覆盖foo1

因此,我认为虚拟函数的唯一用途是我们想要在运行时更改功能。

在我们想要在运行时更改已执行的类时,它可能在这种情况下有用:

A *a;
B b;
C c;

a = &B;
a->foo1();
a = &C;
a->foo1();

或者,在将参数传递给函数时,这可能很有用:

void execute(A *a)
{
    a->foo1();
}

我错过了一些关于此的事情吗?

2 个答案:

答案 0 :(得分:3)

虚函数是C ++实现运行时多态的主要方式。 Google搜索多态可能会向您展示该技术的用处。

答案 1 :(得分:0)

虚函数是C ++实现多态性概念的方式。

在C ++中,简单方法重载用于编译时多态,其中编译器在编译期间绑定方法。

如果是虚函数,编译器将在运行时和需要时使用这些方法。