1519 votes

Quelqu'un peut m'expliquer C++ Méthodes Virtuelles?

Je suis en train d'apprendre le C++, et je suis juste en Virtuel Fonctions/Méthodes.

De ce que j'ai lu (dans le livre et en ligne), les Méthodes Virtuelles sont des méthodes dans la classe de base que vous pouvez modifier dans les classes dérivées.

Mais plus tôt dans le livre, lors de l'apprentissage sur la base de l'héritage, j'ai été en mesure de remplacer des méthodes de base dans les classes dérivées sans l'aide d' virtual.

Donc ce qui me manque ici? Je sais qu'il y est plus de méthodes virtuelles et il semble être important donc, je veux être clair sur ce qu'il est exactement. Je juste ne pouvez pas trouver une réponse claire en ligne.

2993voto

M Perry Points 2259

Je suis une C++ débutant moi-même, mais voici comment je m'y compris non seulement que les fonctions virtuelles sont, mais pourquoi ils sont requis:

Disons que vous disposez de ces deux classes:

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."; }
}

Dans votre fonction principale:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // outputs: "I'm eating generic food."
cat->eat();    // outputs: "I'm eating a rat."

Jusqu'ici tout va bien, non? Les animaux mangent les génériques de la nourriture, les chats mangent des rats, sans virtual.

Nous allons changer un peu maintenant de sorte que eat() est appelé par le biais d'un intermédiaire de la fonction (un triviaux de la fonction juste pour cet exemple):

//this can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

Maintenant notre fonction principale est:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal) // outputs: "I'm eating generic food."
func(cat)    // outputs: "I'm eating generic food."

Uh oh...nous avons passé un Chat en func(), mais il l'habitude de manger des rats. Si vous surcharge func() donc il faut un Chat* ? Si vous avez à tirer plus d'animaux de l'Animal, ils seraient tous besoin de leur propre func().

La solution est de faire eat() une fonction virtuelle:

class Animal
{
public:
virtual void eat() { std::cout << "I'm eating generic food."; }
}

Principales:

func(animal) // outputs: "I'm eating generic food."
func(cat)    // outputs: "I'm eating a rat."

Fait.

757voto

Steve314 Points 12599

Sans "virtuel", vous obtenez "la liaison anticipée". La mise en œuvre de la méthode utilisée, qui se décide au moment de la compilation en fonction du type du pointeur que vous appelez à travers.

Avec "virtuel", vous obtenez "late binding". La mise en œuvre de la méthode utilisée se décide au moment de l'exécution en fonction du type de la pointe-de l'objet qu'il a été construit à l'origine. Ce n'est pas nécessairement ce que vous pensez en fonction du type du pointeur qui pointe vers l'objet.

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"

EDIT - voir cette question.

Aussi - ce tutoriel couvre début et à la fin de la liaison en C++.

89voto

Henk Holterman Points 153608

Vous avez besoin d'au moins 1 niveau de l'héritage, et une triste pour le démontrer. Voici un exemple très simple:

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
}

39voto

Alex Martelli Points 330805

Si la classe de base est de Base, et une classe dérivée est - Der, vous pouvez avoir un Base *p pointeur qui pointe effectivement vers une instance d' Der. Lorsque vous appelez p->foo();, si foo est pas virtuelle, alors Bases'version de celui-ci s'exécute, ignorant le fait qu' p souligne en fait à un Der. Si toto est virtuel, p->foo() exécute le "leafmost de" substitution d' foo, tout en tenant pleinement compte de la classe réelle de la pointe-au point. Donc, la différence entre le virtuel et non virtuel est en fait assez crucial: l'ancien permettre l'exécution de polymorphisme, le concept de base de la programmation orientée-objet, tandis que le second ne l'est pas.

23voto

h0b0 Points 998

Vous avez de distinguer entre le remplacement et la surcharge. Sans l' virtual mot-clé, vous ne surchargez une méthode d'une classe de base. Cela ne signifie rien, mais se cacher. Disons que vous avez une classe de base Base et une classe dérivée Specialized qui mettent en œuvre void foo(). Maintenant, vous avez un pointeur vers Base pointant vers une instance d' Specialized. Lorsque vous appelez foo() sur ce que vous pouvez observer la différence qu' virtual fait: Si la méthode est virtuelle, la mise en œuvre de l' Specialized sera utilisée, si elle est manquante, la version de Base sera choisi. Il est conseillé de ne jamais surcharger les méthodes d'une classe de base. Faire une méthode non-virtuel est la manière de son auteur à vous dire que son extension dans les sous-classes n'est pas prévu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X