2012-02-24 5 views
16
class base{ 
    ..... 
    virtual void function1(); 
    virtual void function2(); 
}; 

class derived::public base{ 
    int function1(); 
    int function2(); 
}; 

int main() 
{ 
    derived d; 
    base *b = &d; 
    int k = b->function1() // Why use this instead of the following line? 
    int k = d.function1(); // With this, the need for virtual functions is gone, right? 

} 

No soy ingeniero de CompSci y me gustaría saberlo. ¿Por qué usar funciones virtuales si podemos evitar los punteros de la clase base?Por qué utilizar punteros de clase base para las clases derivadas

Respuesta

47

El poder de polimorfismo no es realmente APPA alquila en tu ejemplo simple, pero si lo extiendes un poco puede ser más claro.

class vehicle{ 
     ..... 
     virtual int getEmission(); 
} 

class car : public vehicle{ 
     int getEmission(); 
} 

class bus : public vehicle{ 
     int getEmission(); 
} 

int main() 
{ 
     car a; 
     car b; 
     car c; 
     bus d; 
     bus e; 

     vehicle *traffic[]={&a,&b,&c,&d,&e}; 

     int totalEmission=0; 

     for(int i=0;i<5;i++) 
     { 
      totalEmission+=traffic[i]->getEmission(); 
     } 

} 

Esto le permite iterar a través de una lista de punteros y tienen diferentes métodos serán llamadas en función del tipo subyacente. Básicamente, le permite escribir código en el que no necesita saber cuál es el tipo de elemento secundario en tiempo de compilación, pero el código tendrá la función correcta de todos modos.

+6

Este es posiblemente uno de los mejores ejemplos para el uso de funciones virtuales. ¡Gracias! – Garfield

+0

Brillante respuesta, pero cuando ya sé que tengo que agregar las Emisiones para todos estos objetos de clase, ¿por qué no puedo crear manualmente los objetos tanto para 'auto' como 'bus' y agregarlos normalmente? ¿Por qué necesito el puntero de tipo de clase base? – Yankee

+0

Supongamos que, si no usamos la función virtual, ¿cuál es el beneficio de utilizar punteros de clase base para la clase derivada? – Rajesh

4

tiene usted razón, si usted tiene un objeto que no es necesario hacer referencia a ella a través de un puntero. Tampoco necesita un destructor virtual cuando el objeto se destruirá según el tipo en que se creó.

La utilidad viene cuando se obtiene un puntero a un objeto de otra pieza de código, y no se sabe muy bien cuál es el tipo más derivado es. Puede tener dos o más tipos derivados creados en la misma base y tener una función que devuelve un puntero al tipo base. Las funciones virtuales le permitirán usar el puntero sin preocuparse por qué tipo derivado está utilizando, hasta que sea el momento de destruir el objeto. El destructor virtual destruirá el objeto sin que usted sepa a qué clase derivada corresponde.

Aquí está el ejemplo más sencillo de utilizar las funciones virtuales:

base *b = new derived; 
b->function1(); 
delete b; 
+1

Creo que su pregunta era por qué el uso de punteros de la clase base y no por eso destructores virtuales –

1

para poner en práctica su polimorfismo. A menos que tenga el puntero de clase base apuntando al objeto derivado, no puede tener polimorfismo aquí.

One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature, that brings Object Oriented Methodologies to its full potential.

In C++, a special type/subtype relationship exists in which a base class pointer or a reference can address any of its derived class subtypes without programmer intervention. This ability to manipulate more than one type with a pointer or a reference to a base class is spoken of as polymorphism.

Subtype polymorphism allows us to write the kernel of our application independent of the individual types we wish to manipulate. Rather, we program the public interface of the base class of our abstraction through base class pointers and references. At run-time, the actual type being referenced is resolved and the appropriate instance of the public interface is invoked. The run-time resolution of the appropriate function to invoke is termed dynamic binding (by default, functions are resolved statically at compile-time). In C++, dynamic binding is supported through a mechanism referred to as class virtual functions. Subtype polymorphism through inheritance and dynamic binding provide the foundation for objectoriented programming

The primary benefit of an inheritance hierarchy is that we can program to the public interface of the abstract base class rather than to the individual types that form its inheritance hierarchy, in this way shielding our code from changes in that hierarchy. We define eval(), for example, as a public virtual function of the abstract Query base class. By writing code such as _rop->eval(); user code is shielded from the variety and volatility of our query language. This not only allows for the addition, revision, or removal of types without requiring changes to user programs, but frees the provider of a new query type from having to recode behavior or actions common to all types in the hierarchy itself. This is supported by two special characteristics of inheritance: polymorphism and dynamic binding. When we speak of polymorphism within C++, we primarily mean the ability of a pointer or a reference of a base class to address any of its derived classes. For example, if we define a nonmember function eval() as follows, // pquery can address any of the classes derived from Query void eval(const Query *pquery) { pquery->eval(); } we can invoke it legally, passing in the address of an object of any of the four query types:

int main() 
{ 
AndQuery aq; 
NotQuery notq; 
OrQuery *oq = new OrQuery; 
NameQuery nq("Botticelli"); // ok: each is derived from Query 
// compiler converts to base class automatically 
eval(&aq); 
eval(&notq); 
eval(oq); 
eval(&nq); 
} 

mientras que un intento de invocar eval() con la dirección de un objeto no derivado de consulta resultados en un error de tiempo de compilación:

int main() 
{ string name("Scooby-Doo"); // error: string is not derived from Query 
eval(&name); 
} 

Within eval(), the execution of pquery->eval(); must invoke the appropriate eval() virtual member function based on the actual class object pquery addresses. In the previous example, pquery in turn addresses an AndQuery object, a NotQuery object, an OrQuery object, and a NameQuery object. At each invocation point during the execution of our program, the actual class type addressed by pquery is determined, and the appropriate eval() instance is called. Dynamic binding is the mechanism through which this is accomplished. In the object-oriented paradigm, the programmer manipulates an unknown instance of a bound but infinite set of types. (The set of types is bound by its inheritance hierarchy. In theory, however, there is no limit to the depth and breadth of that hierarchy.) In C++ this is achieved through the manipulation of objects through base class pointers and references only. In the object-based paradigm, the programmer manipulates an instance of a fixed, singular type that is completely defined at the point of compilation. Although the polymorphic manipulation of an object requires that the object be accessed either through a pointer or a reference, the manipulation of a pointer or a reference in C++ does not in itself necessarily result in polymorphism. For example, consider

// no polymorphism 
    int *pi; 
// no language-supported polymorphism 
    void *pvi; 
// ok: pquery may address any Query derivation 
    Query *pquery; 

In C++, polymorphism exists only within individual class hierarchies. Pointers of type void* can be described as polymorphic, but they are without explicit language support — that is, they must be managed by the programmer through explicit casts and some form of discriminant that keeps track of the actual type being addressed.

+0

la última parte son de C++ imprimación! consiga ese libro y lea en Polimorfismo –

0

Usted parece haber pedido a dos preguntas (en el título y en el final):

  1. Por qué punteros clase base para las clases derivadas uso? Este es el mismo uso del polimorfismo. Le permite tratar objetos de manera uniforme al tiempo que le permite una implementación específica. Si esto te molesta, entonces supongo que deberías preguntar: ¿Por qué el polimorfismo?

  2. ¿Por qué usar destructores virtuales si podemos evitar punteros de la clase base? El problema aquí es no siempre se puede evitar punteros de la clase base para explotar la fuerza de polimorfismo.

Cuestiones relacionadas