我正在开发一个C ++项目,除此之外,我还有一些带有一些纯虚方法的接口。当我尝试实现该接口时出现问题 - IntelliSense似乎不同意派生类的方法声明。这种方法的一个例子:
// DLL_EXPORT -> #define DLL_EXPORT __declspec(dllexport)
// IPlayer
DLL_EXPORT virtual const Grid& GetGrid() const = 0;
其中一个派生类中的声明:
// Human : IPlayer
DLL_EXPORT const Grid& IPlayer::GetGrid() const;
它一直唠叨我的错误 - “IntelliSense:声明必须对应于指定基类中的纯虚拟成员函数”。代码编译没有错误并运行正常,所有“有问题”的方法在运行时按预期执行其工作。值得一提的是,如果我在派生类中删除了IPlayer :: scope限定符,则错误消失。出于可读性原因,我想保留它。另外,我并不精通C ++,所以我提供的例子可能会出现明显错误。
答案 0 :(得分:1)
最小化的例子:
struct C { virtual void f() = 0; };
struct D : C { void C::f() { } };
这不能在我测试的任何版本的g ++或clang中编译。 VS2013中的Intellisense使用EDG前端,并quote Jonathan Wakely,“如果GCC,Clang和EDG都同意,MSVC不同意这通常意味着MSVC是错误的。”
为了使事情变得更有趣,标准中的相关段落实际上在C ++ 11和C ++ 14之间发生了变化。
在C ++ 11中,这是完全违法的(N3337§8.3[dcl.meaning] / p1):
除了a的定义外, declarator-id 不具备资格 成员函数(9.3)或其外部的静态数据成员(9.4) class,函数的定义或显式实例化 命名空间之外的命名空间的变量成员,或者 在其命名空间之外定义显式特化,或 友元函数的声明是另一个类的成员 或命名空间(11.3)。
由于CWG issue 482,此句在C ++ 14中被删除。该问题的拟议决议如下:
[起草说明:这里省略了“同类之外”没有 允许重新申请集体成员;那仍然是 9.2 [class.mem]第1段禁止的。删除 枚举可以使用qualified-id的声明类型 似乎允许typedef声明使用qualified-id,即 以前是不允许的;如果这是不受欢迎的,禁令可以 在这里恢复。]
在C ++ 14中,§8.3[dcl.meaning] / p1中唯一适用的规则现在是(引用N3936):
当 declarator-id 合格时,声明应引用a 以前声明的类或名称空间的成员 限定符指的是(或者,在命名空间的情况下,指的是元素的元素) 该命名空间的内联命名空间集(7.3.1))或特化 物;该成员不仅仅是由一个人介绍的 using-declaration 在由类提名的类或命名空间的范围内 declarator-id 的嵌套名称说明符。
§9.2[class.mem] / p1的相关部分是:
除非用于宣布朋友(11.3)或引入其名称 基类的成员到派生类(7.3.3), member-declarations 声明该类的成员,以及每个成员 member-declaration 应声明至少一个成员名称 类。会员不得两次申报 member-specification ,但嵌套类或成员类除外 模板可以声明然后定义,除了一个 枚举可以通过 opaque-enum-declaration 引入 后来用枚举说明符重新声明。
由于 using-declaration “将基类的成员引入派生类”是一个显式异常,因此基类成员似乎不被认为是成员的目的。规则“ member-declarations 声明该类的成员,并且每个此类 member-declaration 应声明该类的至少一个成员名称”。如果是这样,那么在C ++ 14中也不允许在成员声明中使用 qualified-id ,如void C::f() { }
,因为< em> qualified-id 是指C
的成员,而不是D
的成员。