Supongamos que tengo una clase base,

struct X{
     std::container<class> A;
     std::container<class> B;

     void do_this(...){...};
     void do_that(...){...};

     X(classC something){
          do_this(...);
          do_that(...);
     }
}

Y quiero crear un descendiente, pero solo necesito cambiar un par de líneas en uno de los métodos llamados en el constructor:

struct Y:X{
    void do_this(...){
         // make my changes
    }
}

Ahora, cuando llamo a Y(classC input), debo obtener mi estructura Y según lo previsto, ¿verdad?


¿Cómo haría esto en C ++?

c++
-2
Christopher 6 mar. 2018 a las 22:59

3 respuestas

La mejor respuesta

Ahora, cuando llamo a Y (entrada classC), debería obtener mi estructura Y como estaba previsto, ¿verdad?

Incorrecto. Heredar un constructor no significa que su cuerpo se recrea con las llamadas de función sustituidas por las que sobrecarga. Significa que para construir un Y es suficiente construir el subobjeto X explícitamente a través de ese c'tor. Entonces, en lugar de molestarlo con el reenvío de cosas, debe colocar el código apropiado en Y para usar.

Esto significa, el mismo cuerpo o cuerpo. Y todo lo demás que sea específico de Y se inicializará por defecto.

¿Cómo haría esto en C ++?

En pocas palabras, no puedes hacerlo fácilmente. A menos que juegues con la magia oscura de la plantilla, X::X siempre llamará a X::do_this. También puede mover do_this a otra clase y usar that uno polimórficamente, pero como mencionó, esta no es una opción.

Si desea agregar una llamada a Y::do_this, escriba un código para Y. Pero no reemplazará la llamada a X::do_this, sucederá después. Ese es el modelo de objetos C ++.

2
StoryTeller - Unslander Monica 6 mar. 2018 a las 20:14

Esto es difícil, porque el único buen método sería utilizar las funciones virtual. Sin embargo, esto no es factible aquí, porque los métodos virtual en los constructores se resuelven estáticamente. Esto significa que si tiene la clase A y la clase B : A y ambos han implementado la función virtual foo, cuando llame a foo en el constructor de la clase base, siempre usará implementación de clase base.

El único método es usarlo así:

class A {
public:
    A(whatever) { }
    virtual void initialize() {
        // base class impl
    }
};
class B : public A{
public:
    // if no base default ctor, use
    // B(whatever)
    //     : A(whatever)
    B(whatever) {
    }
    virtual void initialize() override {
        // derived class impl
    }
};

template <typename T> // constraint it if you want.
T createObject() {
    T object;
    object.initialize(); // resolved dynamically
}
1
Poeta Kodu 6 mar. 2018 a las 20:14

Mientras la clase Y herede de la clase X y la clase X no tenga un constructor predeterminado, debe llamar explícitamente a su versión sobrecargada en la clase sobrecargada (Y):

class X{
    public:
        X(int _x) : x(_x){};
    private:
        int x;
};

class Y : public X{
    public:
        Y() : X(0){} // important
};


int main() {

    Y y; // if you remove the default constructor of Y you'll get an error here

    return 0;
}
1
Raindrop7 6 mar. 2018 a las 20:10