Этот код работает соответствующим образом, если я не использую, а затем удаляю указатель для 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 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 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;
}
В этом коде есть несколько основных проблем:
Во-первых, вы не должны использовать множественное наследование для этого. Это совершенно бесполезно и приведет к очень сложному отслеживанию ошибок.
Во-вторых, вам не нужно проверять значение nullptr
перед удалением указателя - он избыточен, поскольку delete
уже делает это.
В-третьих, ни один из ваших базовых классов не имеет виртуального деструктора. (текущая ошибка)
В-четвертых, вы нарушаете правило 3 в своем классе Output
(и, вероятно, вам нужно будет использовать его во всех них).
В-пятых, предполагая, что string
означает std::string
. Нет причин для того, чтобы это была string*
- просто используйте std::string
и избегайте выделять и освобождать ее.
Я не исправлял проблемы с дизайном, но здесь исправлены проблемы с доступом к памяти и полиморфными проблемами.
#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 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 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;
}
EDIT: пример лучшего способа реализации желаемой программы можно найти здесь.
Polygon
класса Output
и Polygon
должны быть virtual
:
class Output {
private:
std::string* myString;
public:
// ...
virtual ~Output() {
// ^^^^^^^
}
};
Также обратите внимание: вместо использования указателя std::string*
вы можете просто использовать std::string myString;
член:
private:
std::string myString;
и оставьте delete myString;
чтобы получить new string()
и delete myString;
право для любых случаев.
delete myString
, это не приводит к утечке памяти? Фактическая ошибка была вызвана отсутствием виртуальных деструкторов в базовом классе, распределение std :: string работало правильно.