una significado qué que programación programacion poo paso parámetros parametros parametro informatica función funciones formales argumentos argumento c++

c++ - significado - qué es un parametro de una función en programación



comportamiento de los argumentos predeterminados de la función virtual (6)

Tengo una situación extraña con respecto al siguiente código. Por favor, ayúdame a aclararlo.

class B { public: B(); virtual void print(int data=10) { cout << endl << "B--data=" << data; } }; class D:public B { public: D(); void print(int data=20) { cout << endl << "D--data=" << data; } }; int main() { B *bp = new D(); bp->print(); return 0; }

En cuanto a la salida que esperaba

[ D--data=20 ]

Pero en la práctica es

[ D--data=10 ]

Por favor ayuda. Puede parecer obvio para ti, pero no conozco el mecanismo interno.


El enlace dinámico usa vpointer y vtable. Sin embargo, el enlace dinámico solo se aplica al puntero de función. No hay ningún mecanismo para el argumento de vinculación dinámica.

Por lo tanto, el argumento predeterminado se determina estáticamente en el momento del compilador. En este caso, está estáticamente determinado por el tipo de bp, que es un puntero a la clase Base. Por lo tanto, data = 10 se pasa como argumento de la función, mientras que el puntero de la función apunta a la función del miembro de la clase derivada: D :: print. Esencialmente, llama a D :: print (10).

El siguiente fragmento de código y las salidas resultantes demuestran claramente el punto: aunque llama a Derived :: resize (int), la función del miembro de la llamada Derivada, pasa el argumento predeterminado de la clase Base: size = 0.

virtual void Derived :: resize (int) tamaño 0

#include <iostream> #include <stdio.h> using namespace std; #define pr_dbgc(fmt,args...) / printf("%d %s " fmt "/n",__LINE__,__PRETTY_FUNCTION__, ##args); class Base { public: virtual void resize(int size=0){ pr_dbgc("size %d",size); } }; class Derived : public Base { public: void resize(int size=3){ pr_dbgc("size %d",size); } }; int main() { Base * base_p = new Base; Derived * derived_p = new Derived; base_p->resize(); /* calling base member function resize with default argument value --- size 0 */ derived_p->resize(); /* calling derived member function resize with default argument default --- size 3 */ base_p = derived_p; /* dynamic binding using vpointer and vtable */ /* however, this dynamic binding only applied to function pointer. There is no mechanism to dynamic binding argument. */ /* So, the default argument is determined statically by base_p type, which is pointer to base class. Thus size = 0 is passed as function argument */ base_p->resize(); /* polymorphism: calling derived class member function however with base member function default value 0 --- size 0 */ return 0; } #if 0 The following shows the outputs: 17 virtual void Base::resize(int) size 0 24 virtual void Derived::resize(int) size 3 24 virtual void Derived::resize(int) size 0 #endif


El estándar dice (8.3.6.10):

Una llamada de función virtual (10.3) usa los argumentos predeterminados en la declaración de la función virtual determinada por el tipo estático del puntero o referencia que denota el objeto. Una función primordial en una clase derivada no adquiere argumentos predeterminados de la función que anula.

Esto significa que, como llama a print través de un puntero de tipo B , usa el argumento predeterminado de B::print .


El valor de argumento predeterminado se pasa en nombre de la persona que llama. Desde el punto de vista de la persona que llama, funciona con la clase B (no con D), por lo que pasa a 10 (como para la clase B)


En general, se utilizan los argumentos predeterminados que son visibles en un determinado ámbito. Puedes hacer (pero no deberías) cosas funky:

#include <iostream> void frob (int x) { std::cout << "frob(" << x << ")/n"; } void frob (int = 0); int main () { frob(); // using 0 { void frob (int x=5) ; frob(); // using 5 } { void frob (int x=-5) ; frob(); // using -5 } }

En su caso, la firma de la clase base es visible. Para usar los argumentos por defecto derivados, debe llamar explícitamente a esa función a través de un puntero a su clase derivada, ya sea al declararlo de esa manera o al lanzarlo correctamente.


Los argumentos predeterminados son completamente en tiempo de compilación. Es decir, la sustitución de los argumentos predeterminados en lugar de los argumentos faltantes se realiza en tiempo de compilación. Por esta razón, obviamente, no hay forma de que la selección del argumento por defecto para las funciones miembro pueda depender del tipo dinámico (es decir, tiempo de ejecución) del objeto. Siempre depende del tipo de objeto estático (es decir, en tiempo de compilación).

El compilador interpretará de inmediato la llamada que escribió en el ejemplo del código como bp->print(10) independientemente de cualquier otra cosa.


su variable es de tipo B, por lo que se llamará a la función de B. Para llamar a D, tienes que declarar tu variable como D o enviarla a D.