在数学,如果z = x+y/2,然后z都是会改变的,每当我们更换的价值x和y。我们可以在编程中做到这一点,而不必z每次更改xand 的值时都进行专门更新y吗?
我的意思是这样的东西行不通,对吧?
int x;
int y;
int z{x + y};
cin >> x;
cin >> y;
cout << z;
Run Code Online (Sandbox Code Playgroud)
如果您对我为什么需要它感到困惑,我希望实时显示该变量,并在rhs变量进行更改时自动更新该变量。
就像杀死一只小怪并获得金币一样,净资产(现金+自己物品的价值)也会发生变化。或者,汽车的速度计会根据您行驶的速度或速度而变化。
Aco*_*gua 57
编辑:在我完全按照要求回答问题时,也请看看Artelius的回答。它解决了我的答案无法解决的一些问题(封装,避免了冗余,悬挂参考的风险)。乔纳森·梅(Jonathan Mee)的答案显示了一种可能的优化方法,如果计算成本很高。
您的意思是这样的:
class Z
{
int& x;
int& y;
public:
Z(int& x, int& y) : x(x), y(y) { }
operator int() { return x + y; }
};
Run Code Online (Sandbox Code Playgroud)
该类将结果的计算延迟到强制转换为int为止。由于强制转换运算符不是显式的,Z因此只要需要int即可使用。由于operator<<for int 有重载,因此可以将其std::cout直接与eg一起使用:
int x, y;
Z z(x, y);
std::cin >> x >> y;
if(std::cin) // otherwise, IO error! (e. g. bad user input)
std::cout << z << std::endl;
Run Code Online (Sandbox Code Playgroud)
但是请注意,即使函数调用不可见,仍然存在一个函数调用(强制转换操作符的隐式调用)。实际上,操作员会执行一些真实的计算(而不只是访问内部成员),因此,隐藏函数调用是否真的是一个好主意是值得怀疑的...
Nat*_*ica 50
您可以通过在C ++中使用lambda来接近这一点。通常,当您设置类似
int x;
int y;
int z{x + y};
Run Code Online (Sandbox Code Playgroud)
z只会是当时的结果x + y。z = x + y;每次更改x或y更新时,您都必须做。
但是,如果使用lambda,则可以让它捕获应引用的对象以及应该执行的计算,然后每次访问lambda时,它将在那个时间点为您提供结果。看起来像
int x;
int y;
auto z = [&](){ return x + y; };
cin >> x;
cin >> y;
cout << z();
Run Code Online (Sandbox Code Playgroud)
并且现在z()将具有正确的值,而不是原始代码具有的未初始化垃圾。
如果计算非常昂贵,您甚至可以在lambda上添加一些缓存,以确保不需要时不运行计算。看起来像
auto z = [&](){ static auto cache_x = x;
static auto cache_y = y;
static auto cache_result = x + y;
if (x != cache_x || y != cache_y)
{
cache_x = x;
cache_y = y;
cache_result = x + y;
}
return cache_result;
};
Run Code Online (Sandbox Code Playgroud)
Ted*_*gmo 25
您可能获得的最接近的结果是创建一个仿函数:
#include <iostream>
int main() {
int x;
int y;
auto z = [&x, &y] { return x + y; }; // a lambda capturing x and y
while(true) {
std::cin >> x;
std::cin >> y;
std::cout << z() << "\n";
}
}
Run Code Online (Sandbox Code Playgroud)
Tob*_*ght 20
有两种主要技术:
递延计算- z使其不是一个简单的变量,而应使其成为一个按需计算值的函数(例如,请参见其他答案)。如果z某些代理对象已隐式转换为所需的类型,则这可以是源代码透明的(如Aconcagua的answer)。
明确的更改通知。这需要x并且y是可观察的类型;当其中一个更改值时,然后z更新自身(并在适用时通知其观察者)。
通常首选第一个版本,但如果需要z成为可观察的类型,第二个版本可能更合适。
Art*_*ius 17
这听起来像XY问题(双关语意)。
从它的声音来看,您并不是真正按照良好的面向对象实践编写代码。我建议您不要使用其他人建议的“技巧”,而要实际学习如何更好地使用OO结构。
在开始讨论之前,请注意赋值与相等关系是不同的。=C ++中的in是赋值,与=数学中的in不同。有一些(但不是很多)编程语言支持相等关系,但是C ++不是其中一种。事实是,增加对平等关系的支持会带来很多新挑战,因此它不像“为什么还没有在C ++中那样简单”。
无论如何,在这种情况下,您可能应该将相关变量封装在一个类中。然后,您可以使用方法来获取“最新”信息。例如:
class Player {
std::vector<int> inventory;
int cash;
public:
int inventory_total();
int net_worth();
}
//adds up total value of inventory
int Player::inventory_total() {
int total = 0;
for(std::vector<int>::iterator it = inventory.begin(); it != inventory.end(); ++it) {
total += *it;
}
return total;
}
//calculates net worth
int Player::net_worth() {
//we are using inventory_total() as if it were a variable that automatically
//holds the sum of the inventory values
return inventory_total() + cash;
}
...
//we are using net_worth() as if it were a variable that automatically
//holds the sum of the cash and total holdings
std::cout << player1.net_worth();
Run Code Online (Sandbox Code Playgroud)
我承认,将这种行为添加到类中比说要复杂得多z = x + y,但这实际上只是几行额外的代码。
如果您忘记在某个地方调用该函数,那将非常烦人并且容易出错。
在这种情况下,对象不具有一个net_worth成员变量,所以你可以不小心使用它,而不是调用函数。
int z(int x, int y)
{
return (x + y);
}
int x;
int y;
// This does ot work
// int z{x + y};
cin >> x;
cin >> y;
cout << z(x, y);
Run Code Online (Sandbox Code Playgroud)
您可以定义以下lambda z,该lambda 始终返回x+y因为x和y被引用捕获的当前值:
int main()
{
int x;
int y;
const auto z = [&x, &y](){ return x+y; };
std::cin >> x; // 1
std::cin >> y; // 2
std::cout << z() << std::endl; // 3
std::cin >> x; // 3
std::cin >> y; // 4
std::cout << z() << std::endl; // 7
}
Run Code Online (Sandbox Code Playgroud)
因此,一个很大的问题,我所提供的解决方案拉姆达看到的是,z在每次它被检查的时间计算,即使没有x,也没有y改变。为了解决这个问题,您确实需要链接这些变量。我建议通过class以下方式进行操作:
class foo {
int x;
int y;
int z;
void calculate() { z = (x + y) / 2; }
friend istream& operator >>(istream& lhs, foo& rhs);
public:
void set_x(const int param) {
x = param;
calculate();
}
int get_x() const { return x; }
void set_y(const int param) {
y = param;
calculate();
}
int get_y() const { return y; }
int get_z() const { return z; }
};
istream& operator >>(istream& lhs, foo& rhs) {
lhs >> rhs.x >> rhs.y;
rhs.calculate();
return lhs;
}
Run Code Online (Sandbox Code Playgroud)
z每次都会重新计算x或y设置。如果您z经常访问x并且y设置得很少,这是一个很好的解决方案。如果x和y被频繁设置或calculate价格昂贵,您可以考虑:
class foo {
int x;
int y;
int z;
bool dirty;
void calculate() { z = (x + y) / 2; }
friend istream& operator >>(istream& lhs, foo& rhs);
public:
void set_x(const int param) {
x = param;
dirty = true;
}
int get_x() const { return x; }
void set_y(const int param) {
y = param;
dirty = true;
}
int get_y() const { return y; }
int get_z() const {
if(dirty) {
calculate();
}
return z;
}
};
istream& operator >>(istream& lhs, foo& rhs) {
lhs >> rhs.x >> rhs.y;
rhs.dirty = true;
return lhs;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我已经包含了一个提取运算符,因此无论您选择哪种代码,都可以将其转换为以下内容:
foo xyz;
cin >> xyz;
cout << xyz.get_z();
Run Code Online (Sandbox Code Playgroud)