c++:new返回一个类型,但编译正常

c++: new return a type but compiles ok

本文关键字:类型 编译 一个 new 返回 c++      更新时间:2023-10-16

我正在测试一个C++程序(演示一个装饰器设计模式),但发现了一个奇怪的问题。示例代码如下所示。错误行错误地有一个额外的new表达式,但令人惊讶的是,代码编译和运行时都有错误输出(decorator输出了两次)。

$ ./a.out
simple window with scroll bar with scroll bar

这里发生了什么事?

#include <iostream>
#include <string>
using namespace std;
class Window {
public:
    virtual string desc() = 0;
    virtual ~Window() {}
};
class SimpleWindow : public Window {
public:
    string desc() { return "simple window"; }
};
class WindowDecorator : public Window {
protected:
    Window *window;
public:
    WindowDecorator(Window *window) : window(window) {}
};
class ScrollBar : public WindowDecorator {
public:
    ScrollBar(Window *window) : WindowDecorator(window) {}
    string desc() { return window->desc() + " with scroll bar"; }
};
int main()
{
    ScrollBar scrollBar = new ScrollBar(new SimpleWindow()); // error line
    cout << scrollBar.desc() << endl;
    return 0;
}

这里有一个例子,说明我们为什么在C++中使用explicit关键字作为构造函数。(参见cppreference.com)

您可以看到,具有单个参数的构造函数,例如ScrollBar类中的构造函数。。。

ScrollBar(Window *window) : WindowDecorator(window) {}

除非标记为explicit,否则编译器将使用它来执行从Window *ScrollBar的隐式转换。这样的构造函数也称为转换构造函数。

那么,这一行发生了什么。。。

ScrollBar scrollBar = new ScrollBar(new SimpleWindow());

是编译器愉快地(隐式)再次调用ScrollBar(Window *window)构造函数,将ScrollBar *(从new ScrollBar()获得)转换为ScrollBar。这是有效的,因为:

  1. ScrollBarWindow的子类(通过WindowDecorator),因此ScrollBar *可以隐式转换为Window *
  2. 构造函数ScrollBar(Window* window)只有一个参数,并且标记为explicit,因此您可以从new ScrollBar()返回的指针中获得ScrollBar的实例

这很可能不是您在编写构造函数时所想的,所以您可能应该将其重写为:

explicit ScrollBar(Window *window) : WindowDecorator(window) {}

这应该会导致令人惊讶的行导致编译错误。在C++中,默认情况下总是将explicit用于单参数构造函数通常是一个好主意,只有在您有意决定允许隐式转换语义时才将其删除。

根据C++标准(4.10指针转换)

3类型为"pointer to cv D"的prvalue,其中D是类类型,可以是转换为"指向cv B的指针"类型的prvalue,其中B是基数D.…的类别(第10条)

和(4个标准转换)

1标准转换是内置的隐式转换意思第4条列举了这类转换的全部内容。A.标准转换序列是中的标准转换序列以下顺序:

--从以下集合转换为零或一:积分促销,浮点提升、积分转换、浮点转换,浮点积分转换,指针转换,指针到成员转换和布尔转换。

在本声明中,

ScrollBar scrollBar = new ScrollBar(new SimpleWindow()); 

在右侧存在可以转换为基类CCD_ 22的指针的派生类CCD_。

ScrollBar具有转换构造函数

ScrollBar(Window *window) : WindowDecorator(window) {}

这在上面的声明中被调用。