Domanda

Ho tre diverse classi base:

class BaseA
{
public:
    virtual int foo() = 0;
};

class BaseB
{
public:
    virtual int foo() { return 42; }
};

class BaseC
{
public:
    int foo() { return 42; }
};

Derivo quindi dalla base in questo modo (sostituisci X con A, B o C):

class Child : public BaseX
{
public:
    int foo() { return 42; }
};

Come viene sovrascritta la funzione nelle tre diverse classi base? I miei tre seguenti presupposti sono corretti? Ci sono altri avvertimenti?

  • Con BaseA, la classe figlio non viene compilata, la funzione virtuale pura non è definita.
  • Con BaseB, la funzione nel figlio viene chiamata quando si chiama foo su un BaseB * o Bambino *.
  • Con BaseC, la funzione nel figlio viene chiamata quando si chiama foo su Child * ma non su BaseB * (viene chiamata la funzione nella classe genitore).
È stato utile?

Soluzione

Nella classe derivata un metodo è virtuale se è definito virtuale nella classe base, anche se la parola chiave virtual non è utilizzata nel metodo della classe derivata.

  • Con BaseA , verrà compilato ed eseguito come previsto, con foo () essendo virtuale ed eseguendo nella classe Child .
  • Lo stesso con BaseB , inoltre verrà compilato ed eseguito come previsto, con foo () essendo virtuale () ed eseguito nella classe Child .
  • Con BaseC , tuttavia, verrà compilato ed eseguito, ma eseguirà la versione BaseC se la chiami dal contesto di BaseC e la versione Child se chiami con il contesto di Child .

Altri suggerimenti

L'importante regola da ricordare è quando una funzione viene dichiarata virtuale, le funzioni con firme corrispondenti nelle classi derivate sono sempre virtuali. Quindi, viene sovrascritto per Child of A e Child of B, che si comporterebbe in modo identico (ad eccezione del fatto che non è possibile istanziare direttamente BaseA).

Con C, tuttavia, la funzione non è ignorata, ma sovraccaricata. In quella situazione, conta solo il tipo statico: lo chiamerà su ciò che è un puntatore a (il tipo statico) invece di ciò che l'oggetto è realmente (il tipo dinamico)

  

Con BaseA, la classe figlio no   compilare, la pura funzione virtuale   non è definito

Questo è vero solo se si tenta di creare un oggetto di BaseA. Se si crea un oggetto di Child e quindi è possibile chiamare foo () utilizzando BaseA * o Child *

  

Con BaseB, la funzione nel figlio   viene chiamato quando si chiama foo su un BaseB *   o Bambino *.

Dipende dal tipo di oggetto in quanto l'oggetto può essere BaseB o Child. Se l'oggetto è BaseB, viene chiamato BaseB :: foo.

  

Con BaseC, la funzione nel bambino   viene chiamato quando si chiama foo su Child *   ma non su BaseB * (la funzione in   viene chiamata la classe genitore).

Sì, ma non vuoi mai farlo.

Dal punto di vista del polimorfismo, preferisci A, quindi sai che ogni bambino ha la propria implementazione della funzione virtuale.
Scegli B principalmente se disponi di un'implementazione predefinita valida, ma devi assicurarti che tutte le classi secondarie abbiano la propria implementazione secondo necessità. C non è polimorfismo, quindi usa con giudizio.

Dipende principalmente da come l'hai chiamato.

se lo hai fatto:

class Child : public BaseA
{
public:
    int foo() { return 42; }
};

e fatto

BaseA baseA = new Child();
baseA->foo();

Chiamerebbe la funzione foo di Child.

Tuttavia, se lo hai fatto:

BaseA baseA = new BaseA();

Produrrebbe un errore in fase di compilazione.

Class Child verrà compilato se derivato da A, non è possibile creare un'istanza di oggetti di quel tipo.

Questo potrebbe essere utile se si volesse sovrascrivere alcune funzioni da Base e poi derivarne di nuovo.

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