2014-02-21 67 views
0

如果我不使用,然後刪除基類Output的指針,此代碼正常工作。 Output的析構函數被調用,似乎可以正常工作。我在這裏錯過了什麼嗎?爲什麼此刪除會導致核心轉儲?

// multiple inheritance 
// Testing overload of muliple inheritance of pure virtual functions. 

#include <iostream> 
#include <string> 

using namespace std; 

class Polygon { 
    protected: 
    int width, height; 
    public: 
    Polygon (int a, int b) : width(a), height(b) {} 
    ~Polygon() = default; 
    virtual int area() = 0; 
}; 

class Output { 
    private: 
    string* myString; 

    public: 
    Output() { 
     myString = nullptr; 
    } 

    Output(const string& s) { 
     myString = new string(s); 
    } 

    // This seems to work, but ther core dump happens right afterwards. 
    ~Output() { 
     cout << "delete called with: " << myString << '\n'; 
     if (myString != nullptr) 
     delete myString; 
    } 
    virtual int area() = 0; 
    void print() { 
     cout << *myString << this->area() << '\n'; 
    } 
}; 



class Rectangle: public Polygon, public Output { 
    public: 
    Rectangle (int a, int b) : Polygon(a,b), Output{"A Rectangle's area is: "} {} 
    int area() { 
    return width*height; 
    } 
}; 

class Triangle: public Polygon, public Output { 
    public: 
    Triangle (int a, int b) : Polygon{a,b}, Output{"A Triangle's area is: "} {} 
    int area() 
     { return width*height/2; } 
}; 

int main() { 
    Output * ptr1 = new Rectangle(4,5); 
    Output * ptr2 = new Triangle(4,5); 

    ptr1->print(); 
    ptr2->print(); 

    // Causes core dump. 
    delete ptr1; 
    delete ptr2; 

    return 0; 
} 

回答

3

沒有與此代碼的幾個主要問題:

首先,你不應該使用多重繼承這一點。這是完全沒有必要的,並且會導致很難追蹤錯誤。

其次,在刪除指針之前,您不需要測試nullptr - 它是多餘的,因爲delete已經這樣做了。

第三,你的兩個基類都沒有虛析構函數。 (你目前的錯誤)

第四,你違反了Output類中的Rule of 3(可能需要在它們中使用它)。

第五,假設string表示std::string。沒有理由成爲string* - 只需使用std::string並避免分配和釋放它。

我沒有修復您的設計問題,但您的內存訪問和多態問題已修復here

#include <iostream> 
#include <string> 

using namespace std; 

class Polygon 
{ 
    protected: 
    int width, height; 
    public: 
    Polygon (int a, int b) : width(a), height(b) {} 
    virtual ~Polygon() { } // needed! 
    virtual int area() = 0; 
}; 

class Output 
{ 
    private: 
    std::string myString; // no need to be a pointer 

    public: 
    Output() { } 

    Output(const string& s) : myString(s) { } 

    virtual ~Output() { } // also needed! 
    virtual int area() = 0; 
    void print() { 
     cout << myString << this->area() << '\n'; 
    } 
}; 



class Rectangle: public Polygon, public Output 
{ 
    public: 
    Rectangle (int a, int b) : Polygon(a,b), Output{"A Rectangle's area is: "} {} 
    int area() { 
    return width*height; 
    } 
}; 

class Triangle: public Polygon, public Output 
{ 
    public: 
    Triangle (int a, int b) : Polygon{a,b}, Output{"A Triangle's area is: "} {} 
    int area() 
     { return width*height/2; } 
}; 

int main() 
{ 
    Output * ptr1 = new Rectangle(4,5); 
    Output * ptr2 = new Triangle(4,5); 

    ptr1->print(); 
    ptr2->print(); 

    // Causes core dump. 
    delete ptr1; 
    delete ptr2; 

    return 0; 
} 

編輯:以實施期望的程序更好的方式的例子可以發現here

+0

使他的析構函數虛擬足以解決我的調試器中的原始問題,但所有的觀點都非常有效,應該加以注意。 – steveg89

+0

這實際上是一個來自cplusplus.com的修改示例,我不認爲我會這樣做繼承。我注意到在你的代碼中你刪除了'delete myString',這不會導致內存泄漏?實際的錯誤是由於缺少基類中的虛擬析構函數造成的,std :: string的分配工作正常。 – MrMowgli

+0

@MrMowgli它不會導致內存泄漏,因爲它也不會動態分配「字符串」。雖然cplusplus.com對標準庫有一些體面的參考,但它提供的許多示例都遠不如體面的代碼。儘管其他一些要點可能還沒有實現*(例如違反動態內存的規則3),只要您嘗試執行諸如「Output obj1 = * obj2」之類的操作, –

2

OutputPolygon類的析構函數應該是virtual也:

class Output { 
    private: 
    std::string* myString; 

    public: 
     // ... 

    virtual ~Output() { 
// ^^^^^^^ 
    } 
}; 

還要注意:而不是使用一個std::string*指針,你可以簡單地用一個std::string myString;成員:

private: 
    std::string myString; 

和留下後面的打擾new string()delete myString;正確的一個y例。

+0

但是,輸出的虛擬析構函數默認情況下是否會調用OUtput的析構函數? – MrMowgli

+0

啊我看到了,它仍然得到適當的調用。謝謝! – MrMowgli

相關問題