这两种说法截然不同,我先说简单(且正确)的说法:
指针
Shape * s = new Circle();
正如您已经提到的,s 在这种情况下是一个 指向Shape 的指针。该语句声明s,并将Circle 类型的指针分配给它。这意味着Circle 派生自Shape。
因为 C++ 是一种多态语言,所以 s 现在确实指向 Circle 类型的对象。如果Shape 具有被Circle 重载的virtual functions,则对s 上的这些函数的调用将被重定向到重载的Circle 实现。
一个简单的不完整的例子(注意在C++中有no by-keyword definedabstract classes):
class Shape{
virtual int getX() = 0; //getX() is purely virtual, so Shape is abstract
}
class Circle : public Shape{
int getX() override;
}
Shape * s = new Circle();
int myX = s->getX(); //will call Circle::getX()
这是基本的多态行为,也是 C++ 中面向对象编程的基石之一。另请注意,override keyword 并非完全必要,我只是个人认为它是一种很好的风格。
对象
Shape s = new Circle();
这个语句看起来几乎和第一个语句一样,但是做的事情完全不同。首先,s 现在是实际对象,既好又坏。这很好,因为它会在当前的compound statement 离开后立即自动销毁,释放它占用的所有内存。
但这很糟糕,因为s 不再是多态的:它被声明为Shape-Object,仅此而已。使用上面的代码,以及 Shape 是一个抽象类的前提,这甚至都行不通。抽象类无法实例化,因为它们具有未实现的功能。
如果我们假设它不是抽象的,就会陷入很多隐式转换的漏洞,我只想简单描述一下:
为了使上述语句成为正确的 C++ 代码,Shape 需要有一个构造函数,该构造函数接受一个类型为 Circle* 的参数,即 not 声明为 explicit。这将使Shape s = new Circle(); 等同于Shape s = Shape(new Circle());。发生implicit conversion。
这是非常,非常糟糕的代码! new Circle() 为永远无法释放的 Circle 对象分配内存,因为它没有名称!这称为内存泄漏,这就是为什么您应该几乎永远在 C++ 中不再使用裸指针的原因。替代方法称为smart pointers,您应该尽可能使用它们。
此外,为防止此类事情发生,您应该声明所有构造函数 explicit(或至少那些只接受一个参数的构造函数):
explicit Shape(Circle *);
最后,我想鼓励你read at least one, better a few books about C++。我刚刚解释的所有内容都是您应该真正了解的超级基础知识,这不是学习它的最佳场所。 C++ 是一种危险的语言,你可能会做很多非常错误的事情,即使它们最初看起来是有效的。