使用虚函数创建实例,为什么?

Instance creation with virtual functions, why?

我对虚函数或方法有疑问。我在 Whosebug link to post 上找到了一个非常好的 post 解释虚函数工作的原因和方式。我现在了解虚拟功能是如何工作的,但我仍然不明白为什么你需要它们。如果您查看 link 和提供的示例,他会创建一个这样的实例:

A *a1 = new B;
a1->show();

但是,如果您想使用 B 中的函数,您为什么要创建这样的实例?为什么不这样做:

B b1 = new B;
b1->show();

当我想使用 B 引用时为什么要使用 A 指针?

我希望你们能理解我不明白的地方,并能向我解释一下。

扩展代码库以包含从 A.

派生的 class C

现在添加一个函数display_A,定义为:

void display_A(A* aPtr)
{
   a->show();
}

您可以将该函数与 B 的实例以及 C 的实例一起使用。

B* bPtr = new B;
C* cPtr = new C;

display_A(bPtr);
display_A(cPtr);

此处,B*C* 在调用 display_A 之前自动转换为 A*display_A 中的 aPtr->show() 无论 aPtr 指向 B 还是 C 都有效。这就是创建 virtual 函数的真正动机。

使用目的

A *a1 = new B;
a1->show();

是为了证明即使指针是A*类型,如果指针指向的确实是一个B对象,B::show()也会被调用。

这是Polymorphism的一个很好的例子。

简而言之,多态性允许两种不同的类型 (类) 提供具有不同底层实现的相同接口。

不以 A 和 B 为例,考虑两个 类 摩托车汽车摩托车汽车都可以驾驶,对吧?您驾驶这两辆车的方式非常不同。 类 都应该提供 drive() 方法,尽管它们的实现不同。

class Vehicle {
    public:
        virtual void drive() = 0;
}

class Car : public Vehicle {
    public:
        void drive() {
            // Driving to work, however a car does that.
        };
}

class Motorcycle : public Vehicle {
    public:
        void drive() {
            // Driving to work, however a motorcycle does that.
        };
}
Vehicle *car = new Car;
Vehicle *motorcycle = new Motorcycle;

// We can both be driven, so we share the same interface.
car->drive();
motorcycle->drive();

这在将对象传递给函数时特别有用。您有一个功能可以实现工作。你真的不在乎你如何你去工作,只要你有某种动力。

void driveToWork(Vehicle *vehicle) {
    vehicle->drive();
}

driveToWork(new Car);

// It's Tuesday, your car broke down!
// As long as we use a Vehicle to get to work, all is well.
driveToWork(new Motorcycle);

最重要的是,当您调用虚函数时,它会执行它可以执行的该函数的最派生形式

class Message
{
     virtual void buildMessage();
}

class ShutdownMessage : public Message
{
     virtual void buildMessage() { /* Do a thing. */ }
}

class StartupMessage : public Message
{
     virtual void buildMessage() { /* Do a totally different thing. */ }
}

void prepareMessage(Message *M)
{
    M->buildMessage();
}

现在你可以这样称呼:

prepareMessage(myMsg);

在任何消息上,它将调用适当的 buildMessage 函数。