Domanda

Sto imparando su C ++ in una classe in questo momento e non ho ben Grok funzioni virtuali puri. Capisco che sono in seguito descritte in una classe derivata, ma perché si vuole dichiarare come uguale a 0 se si sta solo andando a definirlo nella classe derivata?

È stato utile?

Soluzione

In breve, è di rendere la classe astratta, in modo che non possa essere istanziato, ma una classe figlia può ignorare i metodi virtuali puri a formare una classe concreta. Questo è un buon modo per definire un'interfaccia in C ++.

Altri suggerimenti

Ciò impone una classe derivata per definire la funzione.

Ogni classe che contiene un metodo virtuale puro sarà astratto, cioè, non può essere istanziato. Le classi astratte sono utili per definire un certo comportamento principale che sottoclassi dovrebbero condividere, ma permettendo (in realtà, richiedendo) sottoclassi di attuare l'abstract individualmente.

Un esempio di una classe astratta:

class Foo {

    // pure virtual, must be implemented by subclasses
    virtual public void myMethod() = 0;

    // normal method, will be available to all subclasses,
    // but *can* be overridden
    virtual public void myOtherMethod();
};

Una classe in cui ogni metodo è astratto può essere utilizzato come interfaccia, che richiede tutte le sottoclassi di conformarsi all'interfaccia attuando tutti i metodi contenuti in esso.

Un esempio di interfaccia:

class Bar {

    // all method are pure virtual; subclasses must implement
    // all of them
    virtual public void myMethod() = 0;

    virtual public void myOtherMethod() = 0;
};

metodi virtuali puri in C ++ sono fondamentalmente un modo per definire interfacce senza richiedere loro da attuare.

Immaginate voglio modellare diversi tipi di forme, e tutte hanno una zona ben definita. Decido che ogni forma deve ereditare IShape ( "I" per l'interfaccia), e GetArea() includerà un metodo <=>:

class IShape {
    virtual int GetArea();
};

Ora il problema: come dovrei calcolare l'area di una forma se questa forma non ignorare <=>? Cioè, qual è la migliore implementazione di default? Cerchi utilizzano pi * raggio ^ 2, piazze utilizzano lunghezza ^ 2, parallelogrammi e rettangoli uso base altezza *, triangoli usano 1/2 di base * altezza, rombi, pentagoni, ottagoni, ecc utilizzare altre formule.

Allora io dico "se sei una forma è necessario definire un modo per calcolare l'area, ma dannato se so quello che sarà", definendo il metodo puro virtuale:

class IShape {
    virtual int GetArea() = 0;
};

Per aggiungere alla risposta di Steven sudit:

"In breve, è di rendere la classe astratta, in modo che non possa essere istanziato, ma una classe figlia può ignorare i metodi virtuali puri a formare una classe concreta. Questo è un buon modo per definire un'interfaccia in C ++. "

Un esempio di questo sarebbe se si ha una classe di base (forse Forma) che si utilizza per definire un certo numero di funzioni membro che le sue classi derivate possono utilizzare, ma vuole evitare un'istanza di Shape essere dichiarato e obbligare gli utenti a utilizzare solo le classi derivate (che può essere, rettangolo, triangolo, del Pentagono, e così via)

RE: la risposta di Jeff sopra

classi non astratte possono contenere funzioni membro virtuali e un'istanza. Infatti, per sovraccarico funzioni membro ciò è necessario come predefinita C ++ non determina il tipo di runtime una variabile, ma quando definito tramite parola chiave th virtuale, lo farà.

Si consideri questo codice (nota, di accesso, mutatori, costruttori, ecc non sono inclusi per motivi di chiarezza):

class Person{
  int age;

  public:
    virtual void print(){
      cout << age <<endl;
    }
}

class Student: public Person{
  int studentID

  public:
    void print(){
      cout << age << studentID <<endl;
    }
}

Ora, quando si esegue questo codice:

 Person p = new Student();
 p.print();

senza la parola chiave virtuale, solo l'età sarebbe stato stampato, non è l'età e studentID come dovrebbe accadere per la classe Student

(questo esempio si basa su una molto simile da C ++ per i programmatori Java http: //www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X )

@Steven sudit: si è completamente corretta, ho trascurato di includere la successione, doh! Le funzioni di accesso ecc non sono inclusi per mantenere le cose più chiare, e ho fatto che più evidente ora. 3-7-09: tutti i fissi

Essenzialmente, virtuali puri vengono usati per creare un'interfaccia (simile a java). Questo può essere usato come un accordo tra due moduli (o classi, o altro) su ciò che tipo di funzionalità di aspettarsi, senza dover conoscere nulla circa l'attuazione della altro pezzo. Questo permette di collegare e riprodurre pezzi utilizzando la stessa interfaccia, senza dover cambiare nulla nel l'altro modulo che sta utilizzando l'interfaccia facilmente.

Ad esempio:

class IStudent
{
    public:
    virtual ~IStudent(){};
    virtual std::string getName() = 0;
};


class Student : public IStudent
{
    public:
    std::string name;
    std::string getName() { return name; };
    void setName(std::string in) { name = in; };
};

class School
{
    public:
    void sendStudentToDetention(IStudent *in) {
        cout << "The student sent to detention is: ";
        cout << in->getName() << endl;
    };
};

int main()
{
    Student student;
    student.setName("Dave");

    School school;
    school.sendStudentToDetention(&student);
return 0;
}

La scuola non ha bisogno di sapere come impostare il nome di uno studente, tutto ciò che serve sapere è come ottenere il nome dello studente. Fornendo un'interfaccia per studenti per l'attuazione e la scuola di usare, c'è un accordo tra i due pezzi su ciò che la funzionalità è necessario per la scuola per svolgere il suo lavoro. Ora siamo in grado di passare in e fuori diverse implementazioni della classe Student tutto quello che vogliamo senza influenzare la scuola (a patto che implementiamo la stessa interfaccia di volta in volta).

L'idea con classi astratte è che si può ancora avere una variabile dichiarata con quel tipo (ad esempio, è il tipo statico), ma la variabile si riferisce in realtà o di punti per un tipo concreto effettivo (il tipo dinamico).

Quando si richiama un metodo in C ++, il compilatore ha la necessità di fare in modo che il metodo potrebbe essere supportato su tale oggetto.

Per dichiarare la funzione virtuale pura, si sta mettendo un "segnaposto" che il compilatore può utilizzare per dire "oh ... so che qualunque cosa finisce per essere indicato da questa variabile accetterà quella chiamata", perché il cemento reale tipi attueranno esso. Tuttavia, non è necessario fornire un'implementazione nel tipo astratto.

Se non ha dichiarato nulla, allora il compilatore non avrebbe modo efficace di garantire che sarebbe stato attuato da tutti i sottotipi.

Naturalmente, se stai chiedendo perché si vuole fare una classe astratta, c'è un sacco di informazioni in giro su questo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top