void方法中的const-correctness和lambda' trick'

时间:2014-12-17 23:36:31

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

我有一个方法接受一个对象的引用作为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则不能。 / p>

我想要的就是知道如何在不需要const的情况下调用虚方法(原因几乎就是这样,我强迫用户扩展类并覆盖{ {1}}仅调用callable方法的方法,这不是我想要的,当然也可以理解lambda会发生什么以及它的工作原理。

1 个答案:

答案 0 :(得分:5)

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

如果确实需要从const中调用非const成员函数,则需要抛弃constness:

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

但由于至少有两个原因,这是非常危险的

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

  2. 你正在调用一个虚函数,你不一定知道派生类'覆盖肯定不会修改任何东西。虚函数的重点是派生类可以做不同的事情,基类不知道细节。

  3. 我会更改您的设计,以便您要调用的虚函数为const,或caller函数为非const。其他任何事情都很危险。