2010-11-17 18 views
9
class Material 
{ 
public: 
void foo() 
{ 
    cout << "Class Material"; 
} 
}; 

class Unusual_Material : public Material 
{ 
public: 
void foo() 
{ 
    cout << "Class Unusual_Material"; 
} 
}; 

int main() 
{ 
Material strange = Unusual_Material(); 
strange.foo(); //outputs "Class Material" 

return 0; 
} 

Me gustaría que esto dé como resultado que se muestre el "Material de clase inusual" en la consola. ¿Hay alguna manera de lograr esto? En mi programa, tengo una clase Material de la cual se derivan otros materiales más específicos. El método Material :: foo() representa un método en Material que es adecuado para la mayoría de los materiales, pero ocasionalmente, otro foo() necesita definirse para un material con propiedades inusuales.Método de clase derivado de llamada de la referencia de clase base

Todos los objetos en mi programa contienen un campo Material. En caso de que se les asigne un material inusual, me gustaría que se llame al foo derivado e inusual.

Esto es probablemente bastante fácil o imposible, pero no puedo entenderlo de ninguna manera.

Gracias

+1

Como una nota, un código como 'material extraño = Unusual_Material();' puede resultar en el problema de rebanado objeto: http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – birryree

Respuesta

19

Lo que queremos es polimorfismo, y para permitir que para una función que necesita para que sea virtual:

class Material 
{ 
public: 
    virtual void foo() // Note virtual keyword! 
    { 
     cout << "Class Material"; 
    } 
}; 

class Unusual_Material : public Material 
{ 
public: 
    void foo() // Will override foo() in the base class 
    { 
     cout << "Class Unusual_Material"; 
    } 
}; 

Además, el polimorfismo sólo funciona para las referencias y punteros:

int main() 
{ 
    Unusual_Material unusualMaterial; 
    Material& strange = unusualMaterial; 
    strange.foo(); 
    return 0; 
} 

/* OR */ 

int main() 
{ 
    Unusual_Material unusualMaterial; 
    Material* strange = &unusualMaterial; 
    strange->foo(); 
    return 0; 
} 

Lo que tienes en tu fragmento de código será slice the Unusual_Material object:

int main() 
{ 
    // Unusual_Material object will be sliced! 
    Material strange = Unusual_Material(); 
    strange.foo(); 
    return 0; 
} 
+1

¡Ah! gracias por señalar eso. Supongo que olvidé que lo virtual era más que una clase abstracta. ¡Gracias por la rápida respuesta! – user487100

+1

@ user487100: Está bien, siempre que se dé cuenta de lo que salió mal. Sin embargo, recomiendo que retome [un buen libro en C++] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list), ya que cubrirá este tema fundamental en mucho mayor detalle. –

+0

Y tampoco tenía idea de cortar. Pensé que el programa simplemente no tendría acceso a las partes derivadas, pero creo que, cuando no se utiliza una referencia, eso tiene mucho sentido. Gracias por agregar ese bit al final para mi edificación. – user487100

1

Aún mejor explicación sería ..

class Base 
{ 
public: 
void foo()  //make virtual void foo(),have derived method invoked 
{ 
    cout << "Class Base"; 
} 
}; 
class Derived: public Base 
{ 
public: 
void foo() 
{ 
    cout << "Class Derived"; 
} 
}; 
int main() 
{ 
Base base1 = Derived(); 
Base1.foo(); //outputs "Class Base" 
      // Base object, calling base method 

Base *base2 = new Derived(); 
Base2->foo(); //outputs"Class Base",Again Base object calling base method 

// But to have base object, calling Derived method, following are the ways 
// Add virtual access modifier for base foo() method. Then do as below, to //have derived method being invoked. 
// 
// Base *base2 = new Derived(); 
// Base2->foo(); //outputs "Class Derived" . 

return 0; 
} 
Cuestiones relacionadas