200 votes

Les fonctions virtuelles peut-il provoquer les paramètres par défaut ?

Si je déclare une classe de base (ou classe d’interface) et spécifier une valeur par défaut pour un ou plusieurs de ses paramètres, les classes dérivées doivent spécifier les mêmes valeurs par défaut et si non, qui par défaut se manifeste dans les classes dérivées ?

Addendum : je suis également intéressé comment cela peut être traitée à travers différents compilateurs et toute entrée sur « recommandé » dans ce scénario.

249voto

John Dibling Points 56814

Virtuals peuvent avoir des valeurs par défaut. Les valeurs par défaut dans la classe de base ne sont pas héritées par les classes dérivées.

Qui par défaut est utilisée, c'est à dire, la classe de base ou d'une classe dérivée' -- est déterminé par le type statique utilisé pour faire l'appel à la fonction. Si vous appelez par l'intermédiaire d'un objet de classe de base, pointeur ou de référence, la valeur par défaut indiqué dans la classe de base est utilisé. A l'inverse, si vous l'appelez par l'intermédiaire d'un objet de classe dérivée, pointeur ou de référence, les valeurs par défaut indiqué dans la classe dérivée sont utilisés. Il y a un exemple en dessous de la Norme citation qui illustre cela.

Certains compilateurs peuvent faire quelque chose de différent, mais c'est ce que le C++03 et C++11 Normes de dire:

(EDIT: Le C++11 Standard dit exactement la même chose)

8.3.6.10:

Un appel de fonction virtuelle (10.3) utilise les arguments par défaut dans le déclaration de la fonction virtuelle déterminé par le type statique de l'pointeur ou une référence désignant l'objet. Un fonction dominante dans une dérivée la classe n'a pas d'acquérir des arguments par défaut de la fonction qu'il les remplacements. [Exemple:

struct A {
  virtual void f(int a = 7);
};
struct B : public A {
  void f(int a);
};
void m()
{
  B* pb = new B;
  A* pa = pb;
  pa->f(); //OK, calls pa->B::f(7)
  pb->f(); //error: wrong number of arguments for B::f()
}
-end example]

Edit Voici un exemple de programme pour démontrer que les valeurs par défaut sont ramassés. Je suis à l'aide d' structs ici plutôt que d' classes tout simplement pour des raisons de concision -- class et struct sont exactement les mêmes dans presque tous les sens, sauf défaut de visibilité.

#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>

using std::stringstream;
using std::string;
using std::cout;
using std::endl;

struct Base { virtual string Speak(int n = 42); };
struct Der : public Base { string Speak(int n = 84); };

string Base::Speak(int n) 
{ 
    stringstream ss;
    ss << "Base " << n;
    return ss.str();
}

string Der::Speak(int n)
{
    stringstream ss;
    ss << "Der " << n;
    return ss.str();
}

int main()
{
    Base b1;
    Der d1;

    Base *pb1 = &b1, *pb2 = &d1;
    Der *pd1 = &d1;
    cout << pb1->Speak() << "\n"    // Base 42
        << pb2->Speak() << "\n"     // Der 42
        << pd1->Speak() << "\n"     // Der 84
        << endl;
}

La sortie de ce programme (sur MSVC10 et GCC 4.4) est:

Base 42
Der 42
Der 84

50voto

David Thornley Points 39051

C'était le sujet de l'un de Herb Sutter début de Gourou de la Semaine des postes. Je n'ai pas indepen

La première chose qu'il dit sur le sujet est de NE PAS le FAIRE.

Plus en détail, oui, vous pouvez spécifier différents paramètres par défaut. Ils ne fonctionnent pas de la même façon que les fonctions virtuelles. Une fonction virtuelle est appelée sur le type dynamique de l'objet, tandis que les valeurs de paramètre par défaut sont basées sur le type statique.

Compte tenu de

class A {
    virtual void foo(int i = 1) { cout << "A::foo" << i << endl; }
};
class B: public A {
    virtual void foo(int i = 2) { cout << "B::foo" << i << endl; }
};
void test() {
A a;
B b;
A* ap = &b;
a.foo();
b.foo();
ap->foo();
}

vous devriez obtenir A::toto1 B::foo2 B::toto1

13voto

Oktalist Points 2524

C'est une mauvaise idée, car la valeur par défaut des arguments que vous recevrez dépendra de la statique type de l'objet, tandis que l' virtual fonction distribué aux dépendra de la dynamique type.

C'est-à-dire, lorsque vous appelez une fonction avec des arguments par défaut, la valeur par défaut arguments sont substitués au moment de la compilation, indépendamment du fait que la fonction est - virtual ou pas.

@cppcoder offert l'exemple suivant, dans son [fermé] question:

struct A {
    virtual void display(int i = 5) { std::cout << "Base::" << i << "\n"; }
};
struct B : public A {
    virtual void display(int i = 9) override { std::cout << "Derived::" << i << "\n"; }
};

int main()
{
    A * a = new B();
    a->display();

    A* aa = new A();
    aa->display();

    B* bb = new B();
    bb->display();
}

Qui produit la sortie suivante:

Derived::5
Base::5
Derived::9

Avec l'aide de l'explication ci-dessus, il est facile de voir pourquoi. Au moment de la compilation, le compilateur remplace la valeur par défaut des arguments de l'fonctions de membre de la statique des types de pointeurs, de faire son main fonction équivalente à la suivante:

    A * a = new B();
    a->display(5);

    A* aa = new A();
    aa->display(5);

    B* bb = new B();
    bb->display(9);

6voto

Mark B Points 60200

Comme vous pouvez le voir dans les autres réponses de ce sujet est compliqué. Au lieu d'essayer de faire ceci ou de comprendre ce qu'il fait (si vous vous posez maintenant, le responsable devra demander ou rechercher un an à partir de maintenant).

Au lieu de cela, créer un public de non-fonction virtuelle dans la classe de base avec les paramètres par défaut. Ensuite, il appelle un privé ou protégé fonction virtuelle qui n'a pas de paramètres par défaut et il est remplacé dans les classes enfant en tant que de besoin. Ensuite, vous n'avez pas à vous soucier de la question de savoir comment il fonctionne et le code est très évident.

5voto

Jerry Coffin Points 237758

C’est une que vous pouvez probablement trouver assez bien en testant (c.-à-d., c’est une partie suffisamment grand public de la langue que la plupart des compilateurs faire presque certainement les choses et sauf si vous voyez des différences entre les compilateurs, leur production peut être considéré comme assez bien faisant autorité).

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