将对象声明为抽象对象 class

Declare an object as abstract class

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

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

使用示例代码的修改版本,从 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# 中完成吗?

我试过了,但出现错误:

error: invalid new-expression of abstract class type 'Rectangle'

这是在QT内。

如果你想保持你的程序内存安全,你可以这样使用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;
}

In C++ is it possible to declare an object as an abstract class, but then instantiate it to a derived class?

你不能声明一个对象,不。无法实例化抽象 classes。但是,您可以声明一个 reference/pointer 到实现抽象 class 的对象,是的。例如:

Shape *shape;

if (userInput == 'R') {
   shape = new Rectangle();
} else if (userInput == 'T') {
   shape = new Triangle();
}

// etc.

delete shape;

在C++11及之后的版本中,你可以使用std::unique_ptr or std::shared_ptr在指针超出作用域时自动为你调用delete,eg:

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 时将调用正确的派生析构函数20=]指针:

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

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

我需要

// 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;
     }
};