重写虚函数协变返回类型(两个指针)
overriding virtual function covariant return types (both pointers)
我正在尝试覆盖基类函数。派生类型和基类型都返回指针,因此根据我在谷歌和堆栈溢出上阅读的一些帖子,它应该是协变的。
但是,对于以下类MSVC2013:
class PSBaseObject
{
public:
PSBaseObject() {}
virtual ~PSBaseObject() {}
virtual void* data() { return this; }
virtual const void* data() const { return this; }
};
template<typename T>
class PSObject : public PSBaseObject
{
private:
T* data_;
public:
PSObject(T* object) : data_(object) {}
~PSObject() { delete data_; }
T* data() { return data_; }
const T* data() const { return data_; }
};
我收到一个错误:
'PSObject<data>::data': overriding virtual function return type differs and is not covariant from 'PSBaseObject::data'
其中数据定义和使用方式如下:
typedef struct
{
void* hFileMap;
void* pData;
std::size_t size;
} data;
data* info = new data();
auto ptr = new PSObject<data>(info);
为什么它不是协变的?
知道我在MSVC2013
做错了什么吗?代码在g++ 4.8.1
中编译并工作正常。
MSVC 是对的;void*
与T*
不协变。引用标准(10.3 [class.virtual],第 7 节):
应与重写函数的返回类型相同 函数或与函数类的协变。如果函数
D::f
覆盖函数B::f
, 如果函数的返回类型满足以下条件,则它们是协变的:— 两者都是指向类的指针,都是对类的左值引用,或者都是对 类
— 返回类型B::f
中的类与返回类型
D::f
中的类相同,或者是一个 返回类型中类的明确且可访问的直接或间接基类D::f
— 指针或引用具有相同的 CV 资格和返回类型中的类类型
D::f
与返回类型中的类类型具有相同或更少的简历资格B::f
。
void
不是T
(=data
) 的基类,因此返回类型不是协变的。
那么为什么会有这个规则呢?好吧,这个想法是,如果你有
struct B {
virtual U* f();
};
struct D : B {
virtual V* f();
};
B* b1 = new B();
B* b2 = new D();
U* u1 = b1->f();
U* u2 = b2->f();
b1->f()
将调用B::f
,返回U*
。但是b2->f()
要调用D::f
,返回V*
。V
必须从U
派生,以便从D::f
返回的V*
始终可以转换为U*
。
现在,在这种情况下允许void
U
是合理的,因为任何指向对象类型的指针都可以转换为void*
,即使void
不是任何东西的基类。但标准并不要求允许。
该标准还规定(1.4 [介绍合规],第 8 段),
符合要求的实现可能有扩展(包括额外的库函数),前提是它们有 不更改任何格式良好的程序的行为。需要实现来诊断以下程序: 使用根据本国际标准格式错误的扩展。然而,在这样做之后, 他们可以编译和执行此类程序。
所以g++没有错。允许U
void
是一个扩展,它不会改变任何格式良好的程序的行为,并且 g++会在您尝试编译此代码时发出警告。
在这种情况下,gcc 是错误的,而 VS 拒绝代码是正确的。该标准在 10.3/7 中处理了这一点,其中定义了协变的含义。该定义要求两个返回类型都是对类的指针或引用。由于void
不是类,因此您提供的代码不显示协方差。
GCC 错误地接受了代码。
MSVC2013是对的。
你什么时候打电话
ptr->data();
编译器将不知道使用什么方法,可能是PSBaseObject::data()
或PSObject<data>::data();
所以你需要修复你的设计。
- 一个对象的两个指针.删除了一个指针,对象仍然存在
- 如何将值添加到嵌套结构中,该结构在C++中有两个指针
- 比较两个指针时">="运算符的奇怪行为
- 根据下面的作者,如果两个指针指向不同的数组,则比较的第一个版本将未定义
- 为什么 fdump-class-hierarchy 为虚函数提供了两个指针 int vtable
- 错误 :"+" 无法添加两个指针
- 使与同一数组无关的两个指针减去未定义行为的基本原理是什么?
- 为什么当我在同一内存中各有两个指针时,我必须调用"delete"两次?
- 如何加入两个指针以将其串在一起并将其存储在数组或字符中
- 如何在多线程 c++ 17 程序中交换两个指针
- 这两个指针怎么能有相同的值
- 为什么两个指针都有相同的内存地址
- 两个指针之间的差异是合法的 c++17 常量表达式
- 为什么两个指向相同链接的两个指针在这里表现不同
- 这两个指针代码有什么区别
- 使用指针在Qt Creator UI中的其他两个指针之间切换
- 重写虚函数协变返回类型(两个指针)
- 想要一种在C++中交换两个指针的有效方法
- 在delete()之后不会断言两个指针都指向NULL
- 更改指针指向指针的位置,同时保持其他两个指针的值