我正在学习 C ++ 而我正在进入虚拟功能。
根据我的阅读(在书中和在线),虚函数是基类中的函数,您可以在派生类中重写它们。
但是在本书前面,当学习基本继承时,我能够在不使用virtual
情况下覆盖派生类中的基本函数。
那我在这里错过了什么?我知道虚拟功能还有更多功能,而且它似乎很重要,所以我想清楚它究竟是什么。我在网上找不到直接答案。
以下是我不仅了解virtual
功能的原因,而且了解为什么需要它们:
假设你有这两个类:
class Animal
{
public:
void eat() { std::cout << "I'm eating generic food."; }
};
class Cat : public Animal
{
public:
void eat() { std::cout << "I'm eating a rat."; }
};
在你的主要功能:
Animal *animal = new Animal;
Cat *cat = new Cat;
animal->eat(); // Outputs: "I'm eating generic food."
cat->eat(); // Outputs: "I'm eating a rat."
到目前为止一切都那么好吧?动物吃普通食物,猫吃老鼠,都没有virtual
。
让我们稍微改变它,以便通过中间函数调用eat()
(这个例子只是一个简单的函数):
// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }
现在我们的主要功能是:
Animal *animal = new Animal;
Cat *cat = new Cat;
func(animal); // Outputs: "I'm eating generic food."
func(cat); // Outputs: "I'm eating generic food."
哦...... 我们把猫送进了func()
,但它不会吃老鼠。你应该重载func()
所以它需要Cat*
吗?如果你必须从 Animal 获得更多的动物,他们都需要自己的func()
。
解决方案是使Animal
类中的eat()
成为一个虚函数:
class Animal
{
public:
virtual void eat() { std::cout << "I'm eating generic food."; }
};
class Cat : public Animal
{
public:
void eat() { std::cout << "I'm eating a rat."; }
};
主要:
func(animal); // Outputs: "I'm eating generic food."
func(cat); // Outputs: "I'm eating a rat."
完成。
如果没有 “虚拟”,你就会得到 “早期绑定”。根据您调用的指针类型,在编译时决定使用该方法的哪个实现。
使用 “虚拟”,您将获得 “后期绑定”。使用该方法的哪个实现在运行时根据指向对象的类型决定 - 它最初构造为什么。根据指向该对象的指针类型,这不一定是您的想法。
class Base
{
public:
void Method1 () { std::cout << "Base::Method1" << std::endl; }
virtual void Method2 () { std::cout << "Base::Method2" << std::endl; }
};
class Derived : public Base
{
public:
void Method1 () { std::cout << "Derived::Method1" << std::endl; }
void Method2 () { std::cout << "Derived::Method2" << std::endl; }
};
Base* obj = new Derived ();
// Note - constructed as Derived, but pointer stored as Base*
obj->Method1 (); // Prints "Base::Method1"
obj->Method2 (); // Prints "Derived::Method2"
编辑 - 看到这个问题 。
此外 - 本教程还介绍了 C ++ 中的早期和晚期绑定。
您需要至少 1 级继承和向下转换来演示它。这是一个非常简单的例子:
class Animal
{
public:
// turn the following virtual modifier on/off to see what happens
//virtual
std::string Says() { return "?"; }
};
class Dog: public Animal
{
public: std::string Says() { return "Woof"; }
};
void test()
{
Dog* d = new Dog();
Animal* a = d; // refer to Dog instance with Animal pointer
cout << d->Says(); // always Woof
cout << a->Says(); // Woof or ?, depends on virtual
}