将对象声明为抽象类



编辑最初发布的这个问题是我所拥有的问题的简化版本,因此不包含导致错误的问题。我已经更新了,更像我的问题,如果其他人有类似的问题,我会发布答案。

在C++中,是否可以将对象声明为抽象类,然后将其实例化为派生类?

以这个示例代码的修改版本为例,从https://www.tutorialspoint.com/cplusplus/cpp_interfaces.htm

class Shape {
public:
// pure virtual function providing interface framework.
virtual int getArea() = 0;
virtual int getNumOfSides() = 0;
void setWidth(int w) {
width = w;
}

void setHeight(int h) {
height = h;
}

protected:
int width;
int height;
};

// Derived classes
class Rectangle: public Shape {
public:
int getArea() { 
return (width * height); 
}
};
class Triangle: public Shape {
public:
int getArea() { 
return (width * height)/2; 
}
};

int main(void) {
Rectangle Rect;
Triangle  Tri;

Rect.setWidth(5);
Rect.setHeight(7);

// Print the area of the object.
cout << "Total Rectangle area: " << Rect.getArea() << endl;
Tri.setWidth(5);
Tri.setHeight(7);

// Print the area of the object.
cout << "Total Triangle area: " << Tri.getArea() << endl; 
return 0;
}

然而,如果我们在编译时不知道Shape的类型,是否可以做一些类似的事情:

Shape *shape;
if (userInput == 'R') {
shape = new Rectangle();
} else if (userInput == 'T') {
shape = new Triangle();
}
// etc.

就像C#中可以做的那样?

我试过了,但出现了错误:

错误:抽象类类型"矩形"的新表达式无效

这在QT范围内。

在C++中,是否可以将对象声明为抽象类,然后将其实例化为派生类?

不能声明对象,否。抽象类不能实例化。但是,您可以声明一个引用/指针,指向实现抽象类的对象,是的。例如:

Shape *shape;
if (userInput == 'R') {
shape = new Rectangle();
} else if (userInput == 'T') {
shape = new Triangle();
}
// etc.
delete shape;

在C++11及更高版本中,当指针超出范围时,可以使用std::unique_ptrstd::shared_ptr为您自动调用delete,例如:

std::unique_ptr<Shape> shape;
if (userInput == 'R') {
shape.reset(new Rectangle);
// or: shape = std::unique_ptr<Shape>(new Rectangle);
// or: shape = std::make_unique<Rectangle>(); // C++14 and later only
} else if (userInput == 'T') {
shape.reset(new Triangle);
// or: shape = std::unique_ptr<Shape>(new Triangle);
// or: shape = std::make_unique<Triangle>(); // C++14 and later only
}
// etc.
std::shared_ptr<Shape> shape;
if (userInput == 'R') {
shape.reset(new Rectangle);
// or: shape = std::make_shared<Rectangle>();
} else if (userInput == 'T') {
shape.reset(new Triangle);
// or: shape = std::make_shared<Triangle>();
}
// etc.

无论哪种方式,只要确保Shape有一个virtual析构函数,这样当delete通过Shape*指针调用派生对象时,就会调用正确的派生析构函数:

class Shape {
public:
virtual ~Shape() {}
// ...
}; 

如果你想保证程序内存的安全,你可以这样使用std::shared_ptr

#include <memory>
template <class T>
using ptr = std::shared_ptr<T>;
class Shape { ... };
class Rectangle: public Shape { ... };
class Triangle: public Shape { ... };

int main() 
{
ptr Rect = std::make_shared<Rectangle>();
ptr Tri = std::make_shared<Triangle>();
// Notice you have to use '->' instead of '.', since those are (smart) pointers
Rect->setWidth(5);
Rect->setHeight(7);
cout << "Total Rectangle area: " << Rect->getArea() << endl;
Tri->setWidth(5);
Tri->setHeight(7);
cout << "Total Triangle area: " << Tri->getArea() << endl; 
// Can't use CTAD as for Rect and Tri. We have to specify 'Shape'.
ptr<Shape> shape;
char userInput;
std::cin >> userInput;
if (userInput == 'R') {
shape = std::make_shared<Rectangle>();
} else if (userInput == 'T') {
shape = std::make_shared<Triangle>();
}
cout << shape->getArea() << endl;
return 0;
}

问题是并非所有由抽象类定义的虚拟函数都在派生类中实现。

我需要

// Derived classes
class Rectangle: public Shape {
public:
int getArea() { 
return (width * height); 
}
int getNumOfSides() {
return 4;
}
};
class Triangle: public Shape {
public:
int getArea() { 
return (width * height)/2; 
}
int getNumOfSides() {
return 3;
}
};

最新更新