void方法中的const-correctness和lambda'技巧'

yay*_*yuj 1 c++ theory lambda c++11 c++14

我有一个方法接受一个对象的引用作为const,这个方法不会改变方法的任何内容,而const表明,这个方法也调用了类中的其他方法,并且是无效的不接受任何参数,也是虚拟的,这意味着扩展基类的类可以覆盖方法,但它也需要是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;
}
Run Code Online (Sandbox Code Playgroud)

输出将是:

I'm being called before the introduce.
Hi.
Run Code Online (Sandbox Code Playgroud)

你可以看到callable必须是const才能被调用.如果我改变并这样做:

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

它将编译而不是抛出错误但是不会调用可调用方法,而是调用虚拟方法,因为它被定义为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;
    }
};
Run Code Online (Sandbox Code Playgroud)

它工作,并callable调用该方法.没有错误passing 'const ...' as 'this' argument.

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

我想要的就是知道如何在不需要const的情况下调用虚方法(原因很简单,我强迫扩展类的用户并覆盖callable方法只调用const方法,这不是我想要的),当然理解lambda会发生什么以及它为什么会起作用.

Jon*_*ely 5

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

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

const_cast<Foo*>(this)->callable();
Run Code Online (Sandbox Code Playgroud)

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

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

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

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