2015-02-26 12 views
6

Una nuova memoria per il mio tipo di classe figlio ereditato dallo strumento della classe base, quando provo ad accedere al secondo elemento del mio array, genera un errore. Le cose vanno bene, quando ho la mia nuova dimensione della matrice è 1Perché non riesco ad accedere alla memoria allocata dinamica nel mio ciclo for?

#include <iostream> 
#include <fstream> 
#include <string> 
using namespace std; 

class Instrument{ 

public: 
    virtual void display(){} 
    virtual void output(){} 
    virtual void readFile(){} 
    virtual ~Instrument(){} 
}; 
class Stock : 
    public Instrument{ 
public: 
    Stock(){ 

    } 
    virtual void input(){ 
     cout << "This is stock, please input its information: "; 
     cin >> name >> bidPrice >> askPrice >> lastPrice >> issueExchange; 
    } 
    virtual void display(){ 
     cout <<"This is to display stock: "<< name << " " 
      << bidPrice << " " 
      << askPrice << " " 
      << lastPrice << " " 
      << issueExchange << " " 
      << endl; 
    } 
    virtual void output(){ 
     ofstream myfile; 
     myfile.open("Stock.txt", ios::out | ios::app); 
     if (myfile.is_open()){ 
      myfile << "This is a stock: " 
       << name << " " 
       << bidPrice << " " 
       << askPrice << " " 
       << lastPrice << " " 
       << issueExchange << " " 
       << endl; 
     } 
     else cout << "Unable to open file"; 
    } 
    virtual void readFile(){ 
     string line; 
     ifstream myfile("Stock.txt"); 
     cout << "\nThis is file stored\n"; 
     if (myfile.is_open()) 
     { 
      while (getline(myfile, line)) 
      { 
       cout << line << '\n'; 
      } 
      myfile.close(); 
     } 
    } 
    virtual ~Stock(){} 
private: 
    char name[13]; 
    double bidPrice; 
    double askPrice; 
    double lastPrice; 
    int issueExchange; 

}; 


int main(){ 

    const int N = 5;//it works fine if I use N=1; 
    Instrument *pBase = NULL; 
    pBase = new Stock[N]; 

    for (int i = 0; i < N; i++){ 
     pBase[i].input();// here throws an exception and ends the program 
     pBase[i].display(); 
     pBase[i].output(); 
    } 
    pBase[N - 1].readFile(); 
    delete[] pBase; 

    system("pause"); 
    return 0; 

} 
+0

@GermaineJason Questo non è Java o C#. Ci sono oggetti e un NPE non esiste. – deviantfan

+0

Interessante, vedo l'errore e sono abbastanza sorpreso di non averlo mai visto prima. È quasi come affettare, ma è diverso. @GermaineJason Ci sono 5 oggetti nella matrice. –

+0

@MooingDuck, è cambiato da stringa a carattere [13], vedi il mio #include Leewis

risposta

7

polimorfismo e l'aritmetica dei puntatori non si mescolano, in quanto la disposizione degli oggetti all'interno di un array dipende dalle dimensioni più di derivazione, e il polimorfismo perde tali informazioni. L'allocazione dinamica è una falsa pista, si può vedere lo stesso problema con:

Derived array[2]; 
Base* p = array; 

printf("%p\n", &array[0]); 
printf("%p\n", p); 
printf("%p\n", &array[1]); 
printf("%p\n", p + 1); 

printf("%z\n", sizeof (array[0])); 
printf("%z\n", sizeof (*p)); 

Si noti che i valori di puntatore utilizzando array stanno muovendo in avanti da sizeof (Derived), ma l'aritmetica dei puntatori utilizzando p si sta muovendo in avanti da sizeof (Base) e non trovare il oggetti reali.

In genere è possibile risolvere questo problema utilizzando un array di Base*, anziché un singolo Base* combinato con l'aritmetica del puntatore.

Base* pp[2]; 
for(auto& elem : array) pp[&elem - array] = &elem; 

printf("%p\n", &array[1]); 
printf("%p\n", pp[1]); 

// use (*pp[1]) or pp[1]->whatever 

Un'altra opzione è quella di utilizzare un oggetto che ricorda il tipo di originale:

Derived* allocated = new Derived[N]; 
std::function<Base& (int)> poly = [allocated](int i){ return allocated[i]; }; 

e utilizzare poly(i) invece di p[i]

Ma avvertimento, non si può fare delete [] &poly(0); perché delete[] non è polimorfica sia .

Utilizzando std::unique_ptr<Derived[]> e std::bind, è possibile organizzare la deallocazione automatica quando l'oggetto accessor alla fine esce dall'ambito.

+3

Sebbene questa risposta sia un po 'carente nella spiegazione, non è vero? –

+0

@MooingDuck: Meglio? –

+0

sì, che il punto, ma il mio incarico mi chiede di usare il polimorfismo e la matrice nello stesso tempo, provo a usare intrument * p [N], e accedo a p [i], ma non funziona qui. Questo è il nuovo modo in cui ho provato – Leewis

1

Sebbene il metodo di Mr.Ben sia assolutamente corretto, ma sento totalmente che il suo C++ e il mio C++ non sono la stessa lingua, qui sta mescolando alcune cose strane, quindi secondo la sua idea, ho provato a modificare il mio codice come Questo.

#include <iostream> 
#include <fstream> 
#include <string> 
#include <vector> 
#include <memory> 
using namespace std; 

class Instrument{ 

public: 
    virtual void display() = 0; 
    virtual void output() = 0; 
    virtual void readFile() = 0; 
    virtual ~Instrument(){}; 
}; 
class Stock : 
    public Instrument{ 
public: 
    Stock(){ 
     cout << "This is stock, please input its information: "; 
     cin >> name >> bidPrice >> askPrice >> lastPrice >> issueExchange; 
    } 
    virtual void display(){ 
     cout << "This is to display stock: " << name << " " 
      << bidPrice << " " 
      << askPrice << " " 
      << lastPrice << " " 
      << issueExchange << " " 
      << endl; 
    } 
    virtual void output(){ 
     ofstream myfile; 
     myfile.open("Stock.txt", ios::out | ios::app); 
     if (myfile.is_open()){ 
      myfile << "This is a stock: " 
       << name << " " 
       << bidPrice << " " 
       << askPrice << " " 
       << lastPrice << " " 
       << issueExchange << " " 
       << endl; 
     } 
     else cout << "Unable to open file"; 
    } 
    virtual void readFile(){ 
     string line; 
     ifstream myfile("Stock.txt"); 
     cout << "\nThis is file stored\n"; 
     if (myfile.is_open()) 
     { 
      while (getline(myfile, line)) 
      { 
       cout << line << '\n'; 
      } 
      myfile.close(); 
     } 
    } 
    virtual ~Stock(){} 
private: 
    string name; 
    double bidPrice; 
    double askPrice; 
    double lastPrice; 
    int issueExchange; 

}; 
class Option : 
    public Instrument{ 
public: 
    Option(){ 
     cout << "This is option, please input its information: "; 
     cin >> name >> uname >> bidPrice >> askPrice >> lastPrice >> contractSize >> exp; 
    } 
    virtual void display(){ 
     cout << "This is to display option: " 
      << name << " " 
      << uname << " " 
      << bidPrice << " " 
      << askPrice << " " 
      << lastPrice << " " 
      << contractSize << " " 
      << exp << " " 
      << endl; 
    } 
    virtual void output(){ 
     ofstream myfile; 
     myfile.open("Option.txt", ios::out | ios::app); 
     if (myfile.is_open()){ 
      myfile << "This is an option: " 
       << name << " " 
       << uname << " " 
       << bidPrice << " " 
       << askPrice << " " 
       << lastPrice << " " 
       << contractSize << " " 
       << exp << " " 
       << endl; 
     } 
     else cout << "Unable to open file"; 
    } 
    virtual void readFile(){ 
     string line; 
     ifstream myfile("Option.txt"); 
     cout << "\nThis is file stored\n"; 
     if (myfile.is_open()) 
     { 
      while (getline(myfile, line)) 
      { 
       cout << line << '\n'; 
      } 
      myfile.close(); 
     } 
    } 
    virtual ~Option(){} 
private: 
    string name; 
    string uname; 
    double bidPrice; 
    double askPrice; 
    double lastPrice; 
    int contractSize; 
    double exp; 
}; 
class Future : 
    public Instrument{ 
public: 
    Future(){ 
     cout << "This is option, please input its information: "; 
     cin >> name >> uname >> bidPrice >> askPrice >> lastPrice >> contractSize >> tickSize >> contractMonth; 
    } 
    virtual void display(){ 
     cout << "This is to display option: " 
      << name << " " 
      << uname << " " 
      << bidPrice << " " 
      << askPrice << " " 
      << lastPrice << " " 
      << contractSize << " " 
      << tickSize << " " 
      << contractMonth << " " 
      << endl; 
    } 
    virtual void output(){ 
     ofstream myfile; 
     myfile.open("Future.txt", ios::out | ios::app); 
     if (myfile.is_open()){ 
      myfile << "This is a future: " 
       << name << " " 
       << uname << " " 
       << bidPrice << " " 
       << askPrice << " " 
       << lastPrice << " " 
       << contractSize << " " 
       << tickSize << " " 
       << contractMonth << " " 
       << endl; 
     } 
     else cout << "Unable to open file"; 
    } 
    virtual void readFile(){ 
     string line; 
     ifstream myfile("Future.txt"); 
     cout << "\nThis is file stored\n"; 
     if (myfile.is_open()) 
     { 
      while (getline(myfile, line)) 
      { 
       cout << line << '\n'; 
      } 
      myfile.close(); 
     } 
    } 
    virtual ~Future(){} 
private: 
    string name; 
    string uname; 
    double bidPrice; 
    double askPrice; 
    double lastPrice; 
    int contractSize; 
    int tickSize; 
    int contractMonth; 
}; 

int main(){ 

    int N = 20; 
    //shared_ptr<Instrument> pBase[N]; 
    vector<shared_ptr<Instrument>> pBase(N); 
    int i = 5; 
    for (i = 0; i < N; i++) pBase[i] = make_shared<Stock>(); 
    for (i = 0; i < N; i++){ 
     pBase[i]->display(); 
     pBase[i]->output(); 
    } 
    pBase[N - 1]->readFile(); 

    for (i = 0; i < N; i++) pBase[i] = make_shared<Option>(); 
    for (i = 0; i < N; i++){ 
     pBase[i]->display(); 
     pBase[i]->output(); 
    } 
    pBase[N - 1]->readFile(); 

    for (i = 0; i < N; i++) pBase[i] = make_shared<Future>(); 
    for (i = 0; i < N; i++){ 
     pBase[i]->display(); 
     pBase[i]->output(); 
    } 
    pBase[N - 1]->readFile(); 

    system("pause"); 
    return 0; 

} 
0

tl; dr risposta: non convertire gamma sottoclasse (Stock[N]) ad un puntatore alla classe base (pBase). Usare sia direttamente Stock*, oppure creare un array di puntatori invece:

auto arr = new Stock*[N]; 
for (int i = 0; i < N; i++) { 
    arr[i] = new Stock(); 
} 

// unrelated but suggested: C++11 unique_ptr is recommended: 
vector<unique_ptr<Stock>> v(N); 

ragioni dettagliate:

1) operatore staffa Array è uno zucchero sintattico: a[b] -> *(a + b);

2) L'aritmetica dei puntatori non è polimorfica, è sempre basata su tipi statici:

pBase[i] -> *(pBase+i) -> *(pBase*)((char*)pBase + sizeof(Instrument) * i); 

3) Questo è, tuttavia, quello che volete:

pBase[i] -> *(pBase+i) -> *(pBase*)((char*)pBase + sizeof(Stock) * i); 

4) Finché sizeof(Instrument) != sizeof(Stock) , sei nei guai.

+0

Sì, vedere la risposta, vettore > pBase (N); – Leewis

Problemi correlati