Domanda

Sto ancora imparando C ++; Stavo cercando come funziona il polimorfismo e ho ottenuto un errore di segmentazione quando si chiama un metodo virtuale.

(Nota: non ho marco il distruttore come virtuale, stavo solo cercando fuori per vedere cosa succede.) Ecco il codice:

#include <iostream>

using namespace std;

class Base
{
protected:
  char *name;

public:
  Base(char *name)
  {
    cout << name << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

Inoltre, se hai altri suggerimenti per quanto riguarda l'utilizzo di ereditarietà e polimorfismo in generale per chi conosce questi concetti in Java, per favore fatemelo sapere. Grazie!

È stato utile?

Soluzione

nome - è unintialized in base

Inoltre si dispone di un altro problema:

  Base c = Child("2");

Non credo che sia quello che vuoi. Il codice sarà creare un'istanza di Base da bambino fuso. Ma penso che si desidera lavorare con un'istanza Bambino sulla base di interfaccia di base; si dovrebbe invece scrivere:

  Base *c = new Child("2");

Inoltre, per evitare errori futuri, dichiarare distruttore in base come virtuale.

Altri suggerimenti

Non si può mai inizializzare la variabile di base nenber - il vostro costruttore di base dovrebbe essere:

Base(char * aname) : name( aname )
  {
    cout << name << ": Base class cons" << endl;
  }

Come pure che, quando si dice

Base b = Child( "xxx" );

quindi l'istanza bambino sarà affettato fino ad una base, che probabilmente non è ciò che si desidera.

Non credo che si sta assegnando il membro char * nome a qualsiasi cosa nel vostro ctors.

Il Bambino :: DISP () metodo non verrà mai chiamato -. C è una variabile di tipo base, e non un puntatore o riferimento, in modo da non verificare la presenza di metodi virtuali

Base * c = new Child("1");
c->disp();
delete c;

chiamerebbe Child :: DISP ().

Whoa lì.

C'è un qualche problema, ma la tua segfault è probabilmente perché si sta passando un char* - che è solo un puntatore, e poi cercando di cout in disp(). Il problema è, che il puntatore non vive in disp(), vive in main(). Probabilmente si desidera sia profonda la copia char*, o utilizzare std::string. Facendo in questo modo non funzionerà.

Modifica :

Vedi EDIT 2

Non si può semplicemente assegnare il nome alla variabile name della classe. Se lo fai, si otterrà risultati imprevedibili - e probabilmente ANCORA segmentation fault. Ricorda: in C / C ++, gli oggetti vengono con ambito locale a meno che non allocato sul mucchio. In questo caso, nella vostra ctor, che ci si vuole fare qualcosa di simile:

this->name = new char[ strlen( name ) + 1 ];
strcpy( this->name, name );

E nel distruttore, si vorrà fare qualcosa di simile:

delete [] this->name;

Nota: la mia sintassi può essere completamente sbagliato, e mi rendo conto il codice di cui sopra è intrinsecamente insicuro in quanto non sta controllando il char* per assicurarsi che non è NULL, e non si sta controllando il valore di ritorno di new. Tuttavia, questo dovrebbe iniziare.

EDIT 2: Mi correggo. stringhe letterali sono trattati come stoccaggio costante e quindi vivono per la durata del programma. Tuttavia , la lezione, credo, è importante: in generale, quando non si tratta di stringhe letterali , passando un puntatore (o un array, ecc), è necessario allocare stoccaggio per esso e profonda-copia. È inoltre necessario de-allocare in modo appropriato quando distruggendo detto oggetto.

Ci sono alcuni problemi qui. La prima cosa è il vostro distruttore classe base deve essere virtuale. In caso contrario, il tuo distruttore della classe base sarà sempre chiamato, anche se punta ad oggetto derivato. In secondo luogo è che non è necessario assegnare oggetto di classe derivata per oggetto classe base. Questo si chiama oggetto affettare. Così, l'assegnazione dovrebbe essere fatto attraverso il puntatore o riferimento.

Il problema di segmentazione sta accadendo perché contiene il valore spazzatura. È necessario inizializzare nel costruttore.

Hai un paio di problemi con il codice.

In primo luogo, e il motivo per cui vostro ottenere un segfault, è l'attuazione del ctor Base prende un parametro con lo stesso nome di una delle variabili membro della classe:

class Base
{
protected:
  char *name;

public:
  Base(char ***name**)
  {
    cout << name << ": Base class cons" << endl;
  }

Il parametro del ctor 'nome' nasconde la variabile di classe membro della stessa, ehm ... nome.

In secondo luogo, si è affettare vostro oggetto qui:

int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

'c' è di tipo base, e si sta tentando di assegnare un bambino ad esso. Tutto il materiale che è unico per bambino sarà tagliati fuori quando si assegna l'ogbject alla classe di base.

Ecco il codice che consente di risolvere entrambi i problemi:

#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
    std::string name_;

public:
  Base(char *name)
      : name_(name) {
    cout << name_ << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name_ << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name_ << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name_ << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name_ << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name_ << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base * c = new Child("2");
  c->disp();
  delete c;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top