我正在制作一个小型塔防游戏以练习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;
}
但当然,我实际上无法在那里访问变量计时器。有没有办法可以做类似的事情?
答案 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;
}
但请注意,您无法指定引用来初始化它,必须初始化它。另请注意,默认情况下C ++不会被重新计数,因此您对精灵的引用很容易成为悬挂参考。
您可能需要考虑std::shared_ptr
而不是参考。