我正在测试C ++程序(演示装饰器设计模式),但是发现了一个奇怪的问题。示例代码如下。错误行错误地有一个额外的new
表达式,但令人惊讶的是,代码编译并运行时输出错误(装饰器输出两次)。
$ ./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
转换。之所以有效,是因为:ScrollBar
是Window
的子类(通过WindowDecorator
),因此ScrollBar *
可以隐式转换为Window *
。构造函数
ScrollBar(Window* window)
具有单个参数,并且未标记为explicit
,因此您可以从ScrollBar
返回的指针中获取new ScrollBar()
的实例。这很可能不是您编写构造函数时所想到的,因此您应该将其重写为:
explicit ScrollBar(Window *window) : WindowDecorator(window) {}
这将导致意外的行导致编译错误。
在C ++中,通常总是对默认的单参数构造函数使用
explicit
是一个好主意,仅当您有意决定允许隐式转换语义时才将其删除。关于c++ - C++:new返回一个类型,但是可以编译,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37263794/