【问题标题】:What is the differenece between Shape s = new Circle(); and Shape * s = new Circle();Shape s = new Circle(); 有什么区别?和 Shape * s = new Circle();
【发布时间】:2014-08-01 11:31:24
【问题描述】:

这是一个面试问题,我们写了Shape s = new Circle();,其中Shapeabstract class

sShape * s = new Circle();这样的形状类型指针有什么区别?

【问题讨论】:

  • 问题中是否提到了特定的语言?
  • 大概这是一个c++ 问题 - 但请编辑您的问题并添加任何合适的语言标签。
  • 是的,这是 C++ 问题。
  • Shape s = new Circle() 应该是一个错误
  • 也许作为面试问题的一部分,他们谈到了如何使用预处理器宏将 Shape 重新定义为指向圆形对象的指针?再说一次,也许不是。

标签: c++ oop


【解决方案1】:

这两种说法截然不同,我先说简单(且正确)的说法:

指针

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++ 是一种危险的语言,你可能会做很多非常错误的事情,即使它们最初看起来是有效的。

【讨论】:

  • 好答案,我还建议原发帖人,如果这些概念令人困惑,那么现在可能不是面试 C++ 工作的合适时机!
【解决方案2】:

new Circle 创建一个Circle 类型的动态对象并给出一个指向它的指针。该指针可用于初始化指向CircleCircle 的任何基类的指针;所以假设Circle派生自Shape,第二种形式

Shape * s = new Circle;

给出一个(静态)类型Shape*的指针,指向一个(动态)类型Circle的对象。这可以多态使用,通过Shape定义的抽象接口与Circle进行交互,而不需要知道实际类型是Circle

第一个不正确的例子

Shape s = new Circle;

尝试创建Shape 类型的对象,并使用指向Circle 的指针进行初始化。由于是抽象的,Shape 不能被实例化,除非作为派生类的一部分,因此无法编译。

当您使用new 时,请务必记住在使用完动态对象后将其发送给delete,或者更好的是,使用诸如智能指针之类的RAII 类来为您处理容易出错的乏味问题。此外,请确保 Shape 具有虚拟析构函数,以便可以安全地删除其派生类型。

【讨论】:

    猜你喜欢
    • 2014-02-23
    • 2014-05-01
    • 2018-08-02
    • 2011-11-22
    • 2012-10-16
    • 2010-12-14
    • 2021-02-26
    相关资源
    最近更新 更多