问题描述
编辑最初发布的这个问题是我所拥有的简化版本,因此不包含导致错误的问题。我已更新为更像我的问题,如果其他人有类似问题,我会发布答案。
在 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_ptr
或 std::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
通过 {{1} } 指针:
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;
}
};