【问题标题】:Why can I not instantiate a const instance of a class when non-const virtual methods are missing?为什么在缺少非常量虚拟方法时不能实例化类的 const 实例?
【发布时间】:2016-12-23 18:32:53
【问题描述】:

为什么这不合法?

class Base {
public:
    virtual void bar() = 0;
    virtual void barc() const = 0;
};

class Derived: public Base {
public:
    // deliberately omitted
    // virtual void bar()
    virtual void barc() const override { };
};

int main() {
    const Derived b;
    b.barc();
    // b.bar();
    // fails as expected with "passing 'const Bar' as 'this' argument discards qualifiers"
}

这失败并出现以下错误,因为我没有定义virtual void bar()

prog.cpp: In function 'int main()':
prog.cpp:16:12: error: cannot declare variable 'd' to be of abstract type 'Derived'
  const Derived d;
            ^
prog.cpp:10:7: note:   because the following virtual functions are pure within 'Derived':
 class Derived : public Base{
       ^
prog.cpp:6:15: note:    virtual void Base::bar()
  virtual void bar() = 0;

但是我无论如何都不能在这里调用bar,因为那个方法没有被标记为const。如果定义了bar,是否有任何合法的方式间接调用d.bar()

  • 是否允许使用const_cast

  • 我在转换超类/子类时会遇到麻烦吗?

如果不是,那我为什么要定义它?

【问题讨论】:

  • 按照编译器错误告诉你的去做。你需要定义bar()
  • @NathanOliver。虽然您显然是正确的,但我认为这不是 OP 的要求。
  • @NathanOliver:我不想定义bar()。我希望声明非常量 Bar 是非法的
  • @Eric。如果您希望定义非常量 Bar 是非法的,那么为什么要添加非常量 bar
  • 啊。我知道你现在从哪里来。基本上为什么不定义一个调用它的函数会是编译器错误是编译器错误。

标签: c++ constants virtual


【解决方案1】:

我认为有几个直截了当的说法:

  1. 因为只有一个 vtable。 const 和非 const 对象共享它。

  2. 因为您可能会将 const 对象 const_cast 转换为非 const 对象。

  3. 因为在构造对象时,它不是 const。

  4. 因为 constness 不是对象本身的属性,它是附加到对象或引用的属性,限制了对对象部分的访问。

进一步的问题是:

是否允许使用 const_cast?

是的。但是你对 const_casted 引用所做的事情会很快导致“未定义的行为”。这并不意味着“世界可能会终结”,正如有些人会让你相信的那样。它的意思是,“c++ 标准没有定义这种行为——如果编译器、硬件或操作系统愿意,这取决于他们”。即,您对 const_casted 引用所做的任何事情都不太可能是可移植的。

我在转换超类/子类时会遇到麻烦吗?

演员表是公开的麻烦。

【讨论】:

  • 是否允许(从定义行为的角度)用const_cast<Derived&>(d); const 抛弃 constness?我认为只有当底层对象是非常量时才允许这样做。
  • @Eric 否,但编译器不需要跟踪允许丢弃常量的位置,以及不允许丢弃常量的位置,因为一般来说,这是不可能的。所以答案是“编译器应该总是期望有人会尝试这样做”
  • @Eric yes... but: "Modifying 通过非常量访问路径修改 const 对象并通过非易失性左值引用易失性对象导致未定义行为。”
  • @Eric 演员阵容并非未定义。改变 const 对象的行为是。但是,未定义并不意味着“绝对禁止”。它只是意味着标准没有定义它。没有什么可以阻止实现或硬件这样做。
  • @Eric: “不能调用非常量方法被解释为突变?或者突变是实际改变字段的行为?” 这是一个很好的问题自己的权利。我相当肯定它涉及对数据成员调用非常量函数。相当。如果您假设的const 成员函数只修改mutable 数据成员怎么办?
【解决方案2】:

您不能实例化抽象类。故事结束。

【讨论】:

  • 如果您认为这是抽象的,那么这只是故事的结尾。我的问题是为什么一个类,其中唯一缺少的方法是在定义的行为下无法调用的方法,仍然被认为是抽象的。
  • “如果你认为这是抽象的,那只是故事的结尾。” 但它是。就是那样子。 C++ 是否可以设计成允许这种边缘情况?也许。会有用吗?疑。它会让很多其他事情变得过于复杂吗?当然。
猜你喜欢
  • 2020-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
相关资源
最近更新 更多