【问题标题】:const-correctness in void methods and lambda 'trick'void 方法和 lambda 'trick' 中的 const 正确性
【发布时间】:2014-12-17 23:36:31
【问题描述】:

我有一个方法接受一个对象的引用作为 const,这个方法不会改变方法的任何内容,而 const 表示,问题是这个方法还调用了类中的其他方法,并且是void,不接受任何参数并且也是虚拟的,这意味着扩展基类的类可以覆盖该方法,但它也需要是 const。例如:

#include <iostream>

class Boz
{
public:
    virtual void introduce() const = 0;
};

class Foo
{
public:
    virtual void callable() const
    {
        // ...
    }

    void caller(const Boz& object) const
    {
        callable();
        object.introduce();
    }
};

class Bar : public Boz
{
public:
    void introduce() const
    {
        std::cout << "Hi." << std::endl;
    }
};

class Biz : public Foo
{
public:
    void callable() const
    {
        std::cout << "I'm being called before the introduce." << std::endl;
    }
};

int main(void)
{
    Biz biz;
    biz.caller(Bar());

    return 0;
}

输出将是:

I'm being called before the introduce.
Hi.

如您所见,callable 必须是 const 才能被调用。如果我改变并这样做:

class Biz : public Foo
{
public:
    void callable()
    {
        std::cout << "I'm being called before the introduce." << std::endl;
    }
};

它会编译不会抛出错误,但不会调用可调用方法,而是定义为 const 的虚拟方法。这很明显。

这里最棘手的部分:

class Foo
{
public:
    virtual void callable()
    {
        // ...
    }

    void caller(const Boz& object) const
    {
        auto trick = [&] () { callable(); };

        trick();

        object.introduce();
    }
};

class Biz : public Foo
{
public:
    void callable()
    {
        std::cout << "I'm being called before the introduce." << std::endl;
    }
};

它有效并且调用了callable 方法。没有像passing 'const ...' as 'this' argument 这样的错误。

我想要做的是调用 callable 而不需要是 const 原因很简单:该方法没有改变任何东西,他无权访问开始传递的对象caller 方法上的参数然后我们假设他不需要是 const 但即使这样编译器也会抛出错误。真正的问题是callable 是虚拟的,类可以扩展基类,实现自己的callable 并尝试调用其他方法,但如果不是const 也不能。

我想要的几乎是,知道如何在不需要 const 的情况下调用虚拟方法(原因几乎是,我有点强迫用户扩展类并覆盖 @ 987654334@ 方法只调用 const 方法,这不是我想要的)当然要了解 lambda 会发生什么以及它为什么起作用。

【问题讨论】:

  • 好吧,你可以将非 const Boz&amp; 传递给 caller,除非你特别想将右值传递给它......
  • 通过将参数声明为 const,您向调用者保证您不会更改参数的状态。如果你将参数传递给一个不做出同样承诺的未知方法,你怎么能尊重这个承诺?
  • Lambda 技巧看起来不应该起作用,因为它有效地丢弃了const 上的thisclang 不接受此代码,但 g++ 接受。你需要const_cast 来做这样的事情,或者,可能更好的主意,重新设计你的代码,这样你就不需要丢弃const
  • But what is happening with the lambda? 一个编译器错误,据我所知。它不应该编译。
  • 你不应该使用const_cast。您应该已经决定是否需要 Foo 常量。如果您确实希望它保持不变,请将const 放在callercallable 上。如果不这样做,请从两者中删除 const。我说的是const,它位于右括号和左括号之间。

标签: c++ c++11 lambda theory c++14


【解决方案1】:

带有 lambda 的代码绝对不应该编译,它只是一个 GCC 错误(报告为 PR 60463PR 60755),现在由 http://gcc.gnu.org/r210292 修复在 svn 主干中

如果你真的需要从 const 调用非 const 成员函数,你需要抛弃 const 性:

const_cast<Foo*>(this)->callable();

但这很冒险,至少有两个原因

  1. 如果对象被声明为const,那么它是未定义的行为,例如const Foo f; f.caller(boz); 是未定义的行为。

  2. 你在调用一个虚函数,你不一定知道派生类的覆盖肯定不会修改任何东西。虚函数的全部意义在于派生类可以做不同的事情,而基类不知道细节。

我会更改您的设计,以便您要调用的虚函数是const,或者caller 函数是非常量的。其他任何事情都是危险的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多