【问题标题】:What is Compiler Generated constructor for abstract class no data members什么是抽象类没有数据成员的编译器生成构造函数
【发布时间】:2015-07-22 18:29:00
【问题描述】:

我正在运行静态分析工具并收到错误,因为没有数据成员的抽象类没有构造函数。

给定一个没有数据成员的抽象类:

class My_Interface
{
  public:
    virtual void interface_function(void) = 0;
};
  1. 编译器是否生成了任何构造函数?
  2. 如果生成构造函数,它的内容是什么?
  3. 如果生成了构造函数,是否会被 优化级别?

静态分析中的规则文档说:
如果你没有在一个类中编写至少一个构造函数,编译器将 默认情况下为您编写一个公共构造函数。此规则检测您是否 不要声明至少一个构造函数。

规则文档参考了 Scott Meyers,“Effective C++: 55 Specific Ways to Improvement your Programs and Design”,第三版。

我的理解是编译器不会为上述情况生成构造函数。

编辑 1:
这不是许多构造函数问题的重复,因为:

  1. 这个没有数据成员。
  2. 这不是询问是否需要构造函数,而是询问会发生什么 当没有提供构造函数时。
  3. 这是 C++ 语言。

【问题讨论】:

  • @DieterLücking:析构函数不是虚拟的,为什么要出现在vtable中?此外,vtable 应该有一个 interface_function 条目
  • @DieterLücking:“优化离开”会发生在“无优化”(或调试)设置吗?

标签: c++ constructor abstract-class language-lawyer static-analysis


【解决方案1】:

即使在这种情况下,编译器至少在理论上合成了一个构造函数。即使你不能创建这个类的实例,构造函数也会在创建派生类的过程中被调用(它会覆盖interface_function,所以它可以被实例化)。

鉴于这基本上是一个纯接口类,构造函数可能不会做任何事情,所以大多数编译器可能会优化它(即使你没有告诉它优化代码也很有可能)。

【讨论】:

  • 那么为了消除构造函数的生成,我应该使用声明私有构造函数和析构函数的习语吗?
  • @ThomasMatthews:如果您将构造函数/析构函数声明为私有,则编译器不应允许您实例化派生类的对象,除非您将其声明为好友它访问那些私人成员。然而,在许多情况下,这纯粹是理论上的——默认情况下,许多编译器不会对省略的成员实施访问限制。
  • @JerryCoffin:这些案例到底是什么?哪个编译器不会为class Base { private: Base() {} }; class Derived : public Base {}; int main() { Derived d; } 生成诊断?
  • @ChristianHackl:我可能措辞不佳。我不确定是否有任何编译器曾经允许这种特定情况,但至少一些较旧的编译器对模糊相似的限制松懈了。我并不是要说:“即使不合法,您的编译器也可能会允许这样做”,而几乎与“避免这样做,即使您的编译器不会阻止您这样做”一样多。
【解决方案2】:
  1. 编译器是否生成了任何构造函数?

是的。一些。首先,来自[class.ctor]:

类 X 的 默认 构造函数是类 X 的构造函数,它要么没有参数,要么每个 不是函数参数包的参数具有默认参数。如果没有用户声明的构造函数 对于类 X,没有参数的非显式构造函数被隐式声明为默认值 (8.4)。 隐式声明的默认构造函数是其类的内联公共成员。默认的默认值 类 X 的构造函数在以下情况下被定义为已删除:

下面有几个要点,但没有一个适用。所以我们有相当于:

My_Interface() = default;

那么,从[class.copy]:

如果类定义没有显式声明复制构造函数,则隐式声明非显式构造函数。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的副本 构造函数被定义为删除;否则,它被定义为默认(8.4)。

所以我们有:

My_Interface(const My_Interface&) = default;

还有:

如果类 X 的定义没有显式声明移动构造函数,则将隐式声明一个非显式构造函数 当且仅当
声明为默认 (9.1) — X 没有用户声明的复制构造函数,
(9.2) — X 没有用户声明的复制赋值运算符,
(9.3) — X 没有用户声明的移动赋值运算符,并且
(9.4) — X 没有用户声明的析构函数。

所以我们也有:

My_Interface(My_Interface&& ) = default;
  1. 如果生成构造函数,它的内容是什么?

三个都生成了,三个都是= default;

  1. 如果生成了构造函数,是否会被优化级别淘汰?

三个构造函数都不是微不足道的,因为My_Interface 有一个虚函数。因此,至少需要初始化/复制 vtable。因此,即使没有任何成员需要初始化/复制/移动,某些事情 也必须发生。

【讨论】:

    【解决方案3】:

    第一季度。有没有编译器生成的构造函数?

    回答:是的。来自 C++11 标准:

    12.1 构造函数

    5 类X默认 构造函数是类X 的构造函数,可以不带参数调用。如果 X 类没有用户声明的构造函数,隐式声明了没有参数的构造函数 默认(8.4)。隐式声明的默认构造函数是其类的 inline public 成员。

    我在标准中没有看到任何可以回答其他两个问题的内容。但是,在您的情况下,由于存在virtual 成员函数,因此默认构造函数至少必须设置对象的虚拟表。

    【讨论】:

    • 1) 这对 C++11 之前的版本仍然有效吗? 2)我的理解是不需要虚拟表。
    • @ThomasMatthews:虚拟表是一个实现概念,而不是语言概念。标准没有提及它们。
    • @ThomasMatthews,我无权访问 C++03 标准。我猜你的问题的答案是“是”。编译器生成默认构造函数对我来说很有意义。绝对需要一个虚拟表。没有它如何实现动态调度?
    猜你喜欢
    • 2016-10-16
    • 2021-10-19
    • 2013-04-09
    • 2020-03-01
    • 2011-10-25
    • 2019-03-15
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    相关资源
    最近更新 更多