std :: function成员可以访问其他成员吗?

时间:2016-05-06 21:04:15

标签: c++ c++11 lambda

我正在制作一个小型塔防游戏以练习C ++。我知道其他语言,但在C ++中做了很少的实际开发。 在这个游戏中我会有几个建筑物,所以我创建了一个类似的课程:

class Building
{
private:
    sf::Sprite& sprite;
    float timer = 0;
    void update(float delta);
};

现在,我将拥有许多不同的建筑,但他们都应该拥有相同的成员。现在,在Java中,我将(必须)为每种不同类型的建筑创建一个子类,我想,我可以将void update(float delta);更改为std::function<void(float)> update;并拥有工厂功能来创建不同的建筑物吗?我的想象是这样的:

在building.h中:

class Building
{
private:
    sf::Sprite& sprite;
    float timer = 0;
    std::function<void(float)> update;
};

在building.cpp中

Building getBuildingA()
{
    Building b;
    b.sprite = /* ... */
    b.update = [](float delta) {
        std::cout << timer++ << std::endl;
    };
    return b;
}

但当然,我实际上无法在那里访问变量计时器。有没有办法可以做类似的事情?

3 个答案:

答案 0 :(得分:2)

您可以进行lambda捕获this。更好的解决方案可能就像

class Building
{
private:
    sf::Sprite& sprite;
    float timer = 0;
    std::function<void(Building*, float)> update_impl;
    void update(float x) { update_impl(this, x); }
};

但实际上,基于您设计的这个片段,您似乎应该使用子类和虚函数;这就是他们的意思

function的典型应用是当您传递函数对象时 - 例如替换使用单个方法编写接口类的Java范例,尤其是在您只需编写函数或lambda而不是整个对象的设置中。

对于对象多态,子类和虚函数的主要替代方法是使用模板和泛型编程 - 尽管这主要是在编译时需要多态发生的时候。 (我想,这对你的情况不合适)

答案 1 :(得分:2)

您只需捕获this 举个例子:

struct S {
    auto foo() {
        return [this](){ this->bar(); };
    }

    void bar() { }
};

int main() {
    S s;
    s.foo()();
}

如果您使用的是C ++ 14,则可以使用初始化列表 举个例子:

#include<cassert>

struct S {
    auto foo() {
        return [timer = timer](){
            assert(timer == 42);
        };
    }

    int timer{42};
};

int main() {
    S s{};
    s.foo()();
}

这样,您将获得一个名为 timer 的复制初始化变量,以便在lambda函数体内使用。

答案 2 :(得分:0)

您可以使用Building的静态成员函数来解决隐私问题,以提供工厂类。

您将要遇到的第二个问题是,您将按值返回Building,因此,除非发生RVO,否则您将无法知道要返回的对象的最终地址。您可以通过让“update()”函数将“this”作为参数传递来解决此问题。

#include <iostream>
#include <functional>

class Building {
    // C++ classes are private by default
    int timer_;
    std::function<void(Building*)> update_;

public:
    void update() {
        update_(this);
    }

    static Building getBuildingA() {
        Building b;
        b.timer_ = 42;
        b.update_ = [](Building* b) {
            b->timer_++;
            std::cout << b->timer_ << '\n';
        };
    }
};

int main() {
    Building b = Building::getBuildingA();
    b.update();
    return 0;
}

工作演示:http://ideone.com/1Jy6zI

但请注意,您无法指定引用来初始化它,必须初始化它。另请注意,默认情况下C ++不会被重新计数,因此您对精灵的引用很容易成为悬挂参考。

您可能需要考虑std::shared_ptr而不是参考。