C ++ vs Java: puntare agli oggetti

1

In Java:

private State current_state;

Poiché "State" è una superclasse, posso quindi assegnare oggetti di sottoclassi a current_state, rendendo effettivamente point_state point a un oggetto diverso:

current_state = low_state;

Qual è l'equivalente di farlo in C ++. La mia comprensione è che i riferimenti non possono puntare a oggetti diversi una volta dichiarati.

La sintassi sopra potrebbe funzionare? Se sì, funzionerebbe nello stesso modo in cui funziona in Java? Anche allora, questa è una buona pratica in C ++?

    
posta M-R 21.05.2016 - 14:37
fonte

3 risposte

3

Se parli di variabili di tipi polimorfici definiti dall'utente, in C ++ devi usare un puntatore o un riferimento per ottenere il polimorfismo di runtime. La sintassi esatta che stai descrivendo è probabilmente legale in C ++ (difficile da dire dato che non hai fornito un esempio completo), ma si traduce in "slicing degli oggetti" piuttosto che polimorfismo.

Il motivo è che una variabile non puntatore / non di riferimento in C ++ indica sempre un oggetto che è archiviato nello stack e ha una struttura nota in fase di compilazione (sebbene quella struttura nota possa includere puntatori a roba sconosciuta ). L'unico modo per compilare il codice usando oggetti con una struttura sconosciuta è usare puntatori o riferimenti a quegli oggetti, poiché la struttura di un puntatore o di un riferimento è la stessa e nota al momento della compilazione, indipendentemente da ciò a cui punta. Questo è il motivo per cui il polimorfismo di runtime deve sempre essere implementato con una sorta di puntatore, indipendentemente dal fatto che la tua lingua scelga di esporre quei puntatori a te. A differenza di Java, il linguaggio C ++ li espone.

Inoltre, i riferimenti possono essere assegnati a più di una volta. Quello che non puoi fare è creare un riferimento non inizializzato , cioè i puntatori possono essere nulli ma i riferimenti non possono.

Esattamente quale sintassi si utilizza dipende dal fatto che si vogliano riferimenti o puntatori grezzi o puntatori intelligenti, che è bisogno di capire in C ++ ma non nei linguaggi raccolti in garbage in Java (sul serio, è non facoltativo, leggi C ++ e / o C ++ moderno efficace per un corso accelerato su questo e altro materiale da richiedere). Ma ecco un semplice esempio per iniziare:

#include <iostream>
#include <memory>
using namespace std;

class Base {
public:
    virtual int foo() {
        return 1;
    };
};

class Derived : public Base {
public:
    int foo() {
        return 2;
    };
};

int main() {
    Base b;
    cout << b.foo() << endl; // prints 1
    Derived d;
    cout << d.foo() << endl; // prints 2

    b = d;
    cout << b.foo() << endl; // prints 1
    // Because b is not a pointer, the Derived object
    // gets "sliced" by the assignment.

    Base& br = b;
    cout << br.foo() << endl; // prints 1

    Base& dr = d;
    cout << dr.foo() << endl; // prints 2 because polymorphism

    unique_ptr<Base> up1 = make_unique<Base>();
    cout << up1->foo() << endl; // prints 1

    unique_ptr<Base> up2 = make_unique<Derived>();
    cout << up2->foo() << endl; // prints 2 because polymorphism

    return 0;
}
    
risposta data 21.05.2016 - 15:36
fonte
1

Se devi essere in grado di assegnare un'istanza di sottoclasse a una variabile in c ++ e hai bisogno di una nuova assegnazione, allora quello che vuoi è un puntatore.

private: State* current_state;

Se è coinvolta la proprietà, dovresti utilizzare un puntatore intelligente come unique_ptr o shared_ptr.

shared_ptr si avvicina di più alla semantica dei riferimenti Java, a parte il fatto che non può gestire i cicli di riferimento

    
risposta data 21.05.2016 - 15:28
fonte
0

Fai ciò che viene chiamato "downcasting". Puoi farlo in C ++, tuttavia, non è raccomandato (imho) a causa dei vari bagagli che C ++ ha che Java non ha.

  1. Il downcasting diretto (come nell'esempio precedente) "separa" i dati derivati quando vengono trasmessi alla classe base. Per evitare ciò, è necessario utilizzare i puntatori.

  2. RTTI. Questa è una funzione in cui puoi determinare il tipo di un oggetto downcast usando std :: typeid e lanciare qualcosa usando dynamic_cast < & gt ;. Tuttavia, molte persone disattivano questa funzione durante la compilazione.

La mia regola generale è che se stai downcast, dovresti ripensare a ciò che stai facendo. Esistono diversi modi per risolvere un problema senza la necessità di manipolare direttamente le classi di base (funzioni virtuali e doppia distribuzione).

    
risposta data 25.07.2016 - 19:09
fonte

Leggi altre domande sui tag