Class properties not holding values - c++

im working in a text-based RPG game, but when I'm setting the values to X variable, when I access that propertie again, it is in its default value, am I doing something wrong?
class Game
{
private:
bool podeAndar;
bool estaBatalhando;
Jogador _jogador;
Mapa _mapa;
public:
Game() { }
Game(Jogador _j){
_jogador = Jogador(_j.getNome());
_mapa.LoadMapa();
podeAndar = true;
estaBatalhando = false;
}
~Game(void)
{
}
Jogador getJogador() {
return _jogador;
}
void setJogador(Jogador v) {
_jogador = v;
}
}
My "Player" class
#pragma once
#include "Criatura.h"
#include <string>
class Jogador :
public Criatura
{
private:
int _cap;
public:
Jogador(std::string nome)
{
setNome(nome);
setCap(150);
}
Jogador() { }
~Jogador(void)
{
}
int getCap(){
return _cap;
}
void setCap(int v){
_cap = v;
}
}
Them my "Main" - when I set the value, when I'm following it in the debugger, it sets the value correctly, but when I access the game.getJogador().getCap() again, it has the default value 150.
int _tmain(int argc, _TCHAR* argv[])
{
Jogador _player = Jogador("Kyore");
Game game = Game(_player);
while(true){
std::cout << game.getJogador().getCap(); //print 150
game.getJogador().setCap(100); //set cap to 100
std::cout << game.getJogador().getCap(); //print 150 again
break;
}
}

In Game class, change this
Jogador getJogador() {
return _jogador;
}
to
Jogador& getJogador() {
return _jogador;
}
And add one more method only to read:
const Jogador& getJogador()const {
return _jogador;
}
Update for the questions asked in the comment
To fix your specific issue of value remaining as 150 inspite of setting a new value, converting the return type to reference is enough.
Why returning reference works?
Because, whenever your original version of getJogador() is called, a copy of the object is
created. Even though you are changing its value, you are actually
changing the value of the temporary object created, not the original
one.
So as your intention is to modify the original object, we need
to access the original one, not its temporary copy. Reference is
the better mechanism in such cases (pointer being the other mechanism, but less safer than reference)
Now about why I suggested the new over load of a const member
function, returning a const reference: this is to highlight to you that it is possible to still get the object without changing its internal state unintentionally. Your sample code does not differentiate between the two getJogador() functions.
So to understand, add these two functions to your Game class:
void DontManipulate()const { std::cout<<getJogador().getCap(); }
void Manipulate() { std::cout<<getJogador().getCap(); }
See the compiler error(s) that you get: - it should throw light on the differences.
Additionally, if you std::cout some message in both the getJogador() functions, you should be able to figure out the differences.

The problem is in your getJogador() method.
In C++, objects can be passed "by value" - which is where the program (usually) copies the object's raw data into a new location, whereas in C# and Java objects are always passed by reference (not counting C#'s structs which are passed by-value similar to C++). C++ will use the "copy constructor" to perform this copy. C++ will create the copy constructor if it isn't explicitly defined in your code, the signature has the form ClassName(ClassName& other);, the default (non-explicit) copy-constructor performs a shallow, member-wise copy operation.
In your case, your getJogador method is returning a copy of your Jogador instance field's data.
Change the method to return a reference or a pointer, like so:
Jogador& getJogador() const {
return _jogador;
}
or
Jogador* getJogador() const {
return &_jogador;
}
The const modifier informs the compiler that this method is not intended to modify the state of your Game class, so the compiler might perform certain optimizations as well as prevent successful compilation if the method does attempt to modify state.

Related

“Setter” method not changing a property, but a test method outputs "test"? (Resubmitted with minimal reproducable example)

Player::Player() {
target = new NPC();
}
NPC Player::getTarget() {
return *target;
}
This is the method that gets the memory address of the current NPC.
NPC::NPC() {
relationship = -35.0;
}
float NPC::getRelationship() {
return relationship;
}
bool NPC::setRelationship(float r) {
relationship = r;
return false;
}
These are the getter and setter functions.
I am using a player class and passing it as argument p to an onTrigger() method:
float rel = p->getTarget().getRelationship();
This is the "getter" being called
cout << p->getTarget().setRelationship(rel - 10.0);
This is the "setter" being called.
I tried to create a test method that simply outputs "test" and I called it in place of the "setter" method. It worked. So the problem must be in the definition of the setter...but it looks perfect :(
This method
NPC Player::getTarget() {
return *target;
}
creates a temporary object of the type NPC. So changing this temporary object does not influence on the object pointed to by target.
If you want to change the original object then you have to return it by reference as for example
NPC & Player::getTarget() {
return *target;
}

Problems with nested object in functional object of the tbb::flow::graph

I have a functional object that I'm using as body for multifunction_node:
class module
{
private:
bool valid;
QString description;
bool hasDetectionBranch;
tDataDescription bufData;
void* dllObject; //<-- This is a pointer to an object constructed with help of the external dll
qint64 TimeOut;
public:
module(const QString& _ExtLibName);
virtual ~module();
void operator() (pTransmitData _transmitData, multi_node::output_ports_type &op);
};
'dllObject' is created at construction time of the object 'module':
module::module(const QString& _ExtLibName) :
valid(true), hasDetectionBranch(false)
{
GetObjectDescription = (tGetObjectDescription)QLibrary::resolve(_ExtLibName, "GetObjectDescription");
CreateObject = (tCreateObject)QLibrary::resolve(_ExtLibName, "CreateObject");
DestroyObject = (tDestroyObject)QLibrary::resolve(_ExtLibName, "DestroyObject");
if (!CreateObject || !DestroyObject || !GetObjectDescription)
valid = false;
else
{
description = QString(GetObjectDescription());
dllObject = CreateObject();
}
}
And this is when 'dllObject' is destroyed:
module::~module()
{
if (valid)
{
DestroyObject(dllObject);
}
}
I've built a little graph:
void MainWindow::goBabyClicked(void)
{
module mod(QString("my.dll")); //<-- Here is OK and mod.dllObject is correct
if (!mod.isValid())
{
qDebug() << "mod is invalid!\n";
return;
}
first fir(input);
folder fol(QString("C:/out"), 10000);
graph g;
source_node<pTransmitData> src(g, fir, false);
multi_node mnode(g, tbb::flow::serial, mod); //<-- WTF? ~module() is executed!
function_node<pTransmitData> f(g, tbb::flow::serial, fol);
make_edge(src, mnode);
make_edge(mnode, f);
src.activate();
g.wait_for_all();
}
So I have 2 questions:
1) Why ~module() is executed and how to prevent this?
2) How to keep pointer for nested object correctly?
UPDATE Added some dummy code to prevent destroying dllObject at first time like:
bool b = false;
module::~module()
{
if (valid && b)
{
DestroyObject(dllObject);
}
if (!b)
b = true;
valid = false;
}
Now it works as expected but looks ugly :/
Max,
I assume you have a typedef of multi_node which is similar to the one in the reference manual example.
The constructor for the multifunction_node has the following signature:
multifunction_node( graph &g, size_t concurrency, Body body );
The body object is copied during the parameter passing and also during the construction of the node, so there are two copies of mod created during construction (actually three, as an initial copy of the body is also stored for re-initializing the body when calling reset() with rf_reset_bodies). The destructor calls you are seeing are probably those used to destroy the copies.
The body object should also have a copy-constructor defined or be able to accept the default-copy-constructor to make copies of the body. I think the QString has a copy-constructor defined, but I don't know about fields like tDataDescription. (I thought we had covered the basic requirements for Body objects in the Reference Manual, but I am still looking for the section.) In any case, the Body class must be CopyConstructible, as it is copied multiple times.
Regards,
Chris

How do I return an immutable parameter from a method, unchanged, and without a copy in c++?

How do I return a parameter from a method, unchanged, and without a copy in c++?
// This is more or less the desired signature from the caller's point of view
SomeImmutableObject ManipulateIfNecessary(SomeImmutableObject const& existingObject)
{
// Do some work…
// ...
if (manipulationIsNeccessary)
{
// Return a new object with new data etc (preferably without another copy)...
return SomeImmutableObject(...);
}
else
{
// Return the original object intact (but with no further copies!)...
return existingObject;
}
}
An example is C#'s String.Trim method. C# strings are immutable and if Trim doesn't have to do any work, a reference to the existing string is returned, otherwise a new string object with the trimmed content is returned.
How would I mimic this semantic in C++ given something close to the above method signature?
Your object must be a reference type for this to work. Let's give a toy example for strings:
class RefString {
public:
RefString() : ref(new std::string()) { }
RefString(const std::string& str) : ref(new std::string(str)) { }
RefString trim_trailing_newline() {
if (ref->back() == '\n') {
return RefString(ref->substr(0, ref->size()-1));
}
return *this;
}
size_t size() { return ref->size(); }
private:
std::shared_ptr<std::string> ref;
};
int main(int argc, char** argv) {
RefString s("test\n");
std::cout << s.size() << "\n";
std::cout << s.trim_trailing_newline().size() << "\n";
return 0;
}
You may always return const SomeImmutableObject&. Note though that assigning result to an object will invoke a copy.
SomeImmutableObject x = ManipulateIfNecessary(y); // will invoke a copy-ctor
The real trick would be the implementation. When the first "if" clause has an effect you will be presumably returning reference to temporary variable (bad thing to do). The newly created object would have to be dynamically allocated.
All, in all I do not think this is easily possible w/o some smart memory management.
A reasonable option is to implement SomeImmutableObject in a way that supports this - internally as a reference-counted smart-pointer to the logical state, while externally it may provide value semantics. (This can complicate usage from threaded code - you may want to read up on copy-on-write (COW) and why it became unpopular for implementing std::string.)
If you're stuck with an existing SomeImmutableObject implementation you can't change, and you can't wrap it with a reference-counted smart-pointer of sorts, then choices get limited.
It doesn't provide as clean caller usage, but you could make manipulationIsNeccessary a caller-accessible function, then have the caller call the "new object with new data" code - in a second function:
SomeImmutableObject obj;
const SomeImmutableObject& o =
manipulationIsNecessary(obj) ? newObjectWithNewData(obj) : obj;
...use o...
By having newObjectWithNewData be a separate function, you should get return value optimisation kicking in (though it's always best to check with your compiler/settings).

Called method is not working C++

I have a class called woodyard. Inside there is a method called collect_wood. It's parameter is a Player object. The method adds 1 to player.wood_resource each time it is called.
I use it in main like this:
for(int i = 0; i < woodyards.size(); i++)
{
woodyards[i].collect_wood(p1);
}
p1 is a player object.
This is the collect_wood method:
void woodyard::collect_wood(Player player)
{
player.wood_resource++;
}
There is no effect on wood_resource when I run it.
Please help. I'm coding in C++ using CodeBlocks
You should use reference here.
void woodyard::collect_wood(Player& player)
{
player.wood_resource++;
}
since in your case - you increment wood_resource of copy.
Do it as Call By Reference. What your code does, it creates new Player each time instead of modifying old one.
void woodyard::collect_wood(Player& player)
{
player.wood_resource++;
}
Note & in void woodyard::collect_wood(Player& player)
You can read more about Function call by reference here
By default the functions are call by value (exceptions are there). If you need to change the original copy and not the temporary object you need to use references or pointers.
You any of the two functions:
void woodyard::collect_wood(Player& player)
{
player.wood_resource++;
}
OR
void woodyard::collect_wood(Player *player)
{
if(player)
{
*player.wood_resource++;
}
}

Passing integer by reference to a class in c++

I have a thread-class Buffer (own made class), and many derived classes such as BufferTypeA, BufferTypeB...
Since I have to synchronize them in a certain order, I'm giving any of them an integer which represents the order to run certain task. I also have to know inside each thread Buffer which one is next to run the task, so I'm passing every BufferType a reference to an integer which all of them must share and I didn't want to make it Global.
I got lost at any point and I don't see where.
First I create all the BufferTypes from a class where I also define that shared integer as:
int currentThreadOrder;
And when creating the BufferTypes:
int position = 0;
if (NULL == bufferA) {
bufferA = new BufferTypeA(&currentThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferB) {
bufferB = new BufferPos(&currentThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferC) {
bufferC = new BufferRtk(&currentThreadOrder, ++position,
waitCondition);
}
Then, in BufferTypeA header:
class BufferTypeA: public Buffer {
public:
BufferTypeA(int currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//..
}
And in cpp file:
BufferTypeA::BufferTypeA(int currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition):
Buffer(currentThreadOrder, threadConnectionOrder, waitCondition) { }
Now I'll show Buffer header:
class Buffer: public QThread {
public:
Buffer(int &currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//...
protected:
QWaitCondition *waitCondition;
int threadConnectionOrder;
int &currentThreadOrder; // Shared address
}
And finally the cpp:
Buffer::Buffer(int &currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition) {
this->threadConnectionOrder = threadConnectionOrder;
this->waitCondition = waitCondition;
this->currentThreadOrder = currentThreadOrder;
}
And the error I'm getting is error: uninitialized reference member Buffer::currentThreadOrder.
I'm embarrased to ask, because it's going to be a simple problem with pointers and addresses, but I can't see where the problem is, so please help.
When you create a class with a data-member that is a reference, the reference needs to be assigned a value in the constructor initializer list.
References have to be given a value when they are created, they are not pointers. They have to start with a value and that value cannot be changed (while the contents that is pointed to by that value can be changed).
Essentially you can think of a reference as an alias for an existing variable. You can't give a friend a nickname if you don't have a friend :)
RESPONSE TO COMMENT:
You don't "share a reference" between objects. Each object will have its own reference to the same variable. When you "pass by reference" you are telling the compiler that you want the variable in your function to actually be the variable in your outer scope, rather than creating a new variable by value. This means that you only have one variable at one memory location. The reference is just memory in some other place that forwards you to that same memory location.
Think of this as call forwarding... I can have 15 phone numbers in 15 different countries. I can set them all up to forward calls to my cell in the US. So, people are calling me no matter which number they call.
Each of your classes just has another reference to forward the "phone calls" or variable reads/writes to that same memory location. So, you're not sharing a reference between classes, you're making sure that each class HAS a reference to the same underlying memory location.
Back to the metaphore, each class won't have the same phone, but each class' phone will forward to the same number (variable) none-the-less which lets them all set/get the same value in the end.
RESPONSE II:
Here's a simple example to get your head going, it's pretty easy to apply to your classes. I didn't compile it but it should work minus a typo or two possibly.
class A
{
public:
A(int& shared) : m_shared(shared)
{
//No actions needed, initializer list initializes
//reference above. We'll just increment the variable
//so you can see it's shared in main.
m_shared += 7;
}
void DoSomethingWithIt()
{
//Will always reflect value in main no matter which object
//we are talking about.
std::cout << m_shared << std::endl;
}
private:
//Reference variable, must be initialized in
//initializer list of constructor or you'll get the same
//compiler error again.
int& m_shared;
};
int main()
{
int my_shared_integer = 0;
//Create two A instances that share my_shared_integer.
//Both A's will initialize their internal reference to
//my_shared_integer as they will take it into their
//constructors "by reference" (see & in constructor
//signature) and save it in their initializer list.
A myFirstA(my_shared_integer);
A mySecondA(my_shared_integer);
//Prints 14 as both A's incremented it by 7 in constructors.
std::cout << my_shared_integer << std::endl;
}
you pass a pointer int* as 1st argument to BufferTypeA, which expects and int, while you said in your question you meant to use a int&. To do this, the ctor of BufferTypeA should take a int& and initialise it in an initialisation list (i.e. not within the { } part of the ctor) like
class BufferType {
int &Ref;
public:
BufferTypeA(int& ref) : Ref(ref) { /* ... */ }
};
and in your construction of BufferA you must not pass an address, but the reference, i.e.
int counter;
Buffer = new BufferType(counter);
You want code like this:
Buffer::Buffer(
int &currentThreadOrder0,
const int threadConnectionOrder0,
QWaitCondition *const waitCondition0
) :
threadConnectionOrder(threadConnectionOrder0),
waitCondition(waitCondition0),
currentThreadOrder(currentThreadOrder0)
{}
The reason is related to the reason you cannot write
const double pi;
pi = 3.14;
but can write
const double pi = 3.14;
A reference is typically implemented as a constant pointer, to which one cannot assign an address after one has initialized the pointer. Your version of the code assigns, as in the first pi example. My version of the code initializes, as in the second pi example.