c++:new返回一个类型,但编译正常
c++: new return a type but compiles ok
我正在测试一个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
。这是有效的,因为:
ScrollBar
是Window
的子类(通过WindowDecorator
),因此ScrollBar *
可以隐式转换为Window *
- 构造函数
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) {}
这在上面的声明中被调用。
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 使用简单类型列表实现的指数编译时间.为什么
- 编译标准库类型
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 非类型指针和引用模板参数,以及在编译时如何/为什么解析它们.c++
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- C++ 编译错误:意外的类型名称"字符串":预期的表达式
- 为什么 std::make_shared 无法编译带有已删除运算符 new 的类型?
- 标量类型的特征模板无法编译固定大小的子矩阵操作
- 在其他容器中使用 boost::container::static_vector 时,GCC 编译错误"将'const s'绑定到类型's&'的引用丢弃限定符"
- 由于类型从 C 转换为 C++,无法编译错误 C2440
- 通过编译时值推断整数的类型
- 基于派生类型的编译时行为分支
- C++ 编译错误:gnu_printf是无法识别的格式函数类型
- 将函数类型作为模板参数传递不会编译
- 枚举类的基础类型别名为整型类型(编译错误)
- 无法将类型转换为类型*-C++编译错误
- 返回仅移动类型编译,即使复制构造函数不可用
- 如何根据模板中的类型编译函数
- 无法使用模板化类型编译 va_arg() 调用,因为模板参数中的逗号