Yuki Matuzaki
Yuki Matuzaki

Reputation: 25

How to get member variable from another class in C++

I want to get public: member variable from another class. But I can't get them. Would you direct me how to do it?

There is hand variable in each class User and Computer.

And I want to get them at doJudge() method's std::cout in class Judge, which means user.hand and computer.hand.

However those value says:

User CHOSE hand in class Judge := 7345888
Computer CHOSE hand in class Judge := 0

This is my code:

#include <iostream>
#include <random>
#include <ctime>

using namespace std;

int random(int low, int high)
{
    return low + rand() % (high - low + 1);
}

class User
{
    public :
        User(){};  //constructor

        int hand;
        void setHand()
        {
            std::cout << "What you choose? (ROCK = 1, SCISSORS = 2, PAPER = 3) := ";
            std::cin>> hand;
        }
};

class Computer
{
    public :
        Computer(){}; //constructor

        int hand;
        void setHand()
        {
            hand = random(1, 3);
            std::cout << "Computer choose := " << hand << std::endl;
        }
};

class Judge
{
    public :
        User user;
        Computer computer;
        
        Judge(){}; //constructor

        void doJudge()
        {
            std::cout << "User CHOSE hand in class Judge := " << user.hand << std::endl;
            std::cout << "Computer CHOSE hand in class Judge := " << computer.hand << std::endl;

        }
};

int main()
{
    srand(time(NULL));

    User user;
    user.setHand();

    Computer computer;
    computer.setHand();

    Judge judge;
    judge.doJudge();
}

compile and execute:

C:\RPS>g++ --version
g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C:\RPS>rps.exe
What you choose? (ROCK = 1, SCISSORS = 2, PAPER = 3) := 2
Computer choose := 2
User CHOSE hand in class Judge := 7345888
Computer CHOSE hand in class Judge := 0

I have spent more than a week but I am giving up.

Please explain to me why I can not get the same values which I and the Computer chose?

Upvotes: -5

Views: 126

Answers (3)

Yuki Matuzaki
Yuki Matuzaki

Reputation: 25

I appreciate you all let me know how to do it. I tried to 3 different way into 1 code, which are value, pointer and reference. Probably still I don't understand them and it's need to be correction in my code, however the compile is pass and I can see what I want to see in the console, so I am grad to it!

//   g++ -o rps.exe rps.cpp

#include <iostream>
#include <random>

int random(int const low, int const high)
{
    static std::mt19937 mt{ std::random_device{}() };
    static std::uniform_int_distribution<int> random_number;
    using param_type = std::uniform_int_distribution<int>::param_type;
    return random_number(mt, param_type{ low, high });
}

class User
{
    public :
        User(){};  //constructor

        int hand;
        void setHand()
        {
            std::cout << "What you choose? (ROCK = 1, SCISSORS = 2, PAPER = 3) := ";
            std::cin>> hand;
        }
};

class Computer
{
    public :
        Computer(){}; //constructor

        int hand;
        void setHand()
        {
            hand = random(1, 3);
            std::cout << "Computer choose := " << hand << std::endl;
        }
};

class Judge_R   //By Reference
{
    public :
        User& user_R;
            Computer& computer_R;

            Judge_R(User& user_R, Computer& computer_R) : user_R(user_R), computer_R(computer_R) {};
        
        void doJudge()
        {
            std::cout << "User CHOSE hand in class Judge_R := " << user_R.hand << std::endl;
            std::cout << "Computer CHOSE hand in class Judge_R := " << computer_R.hand << std::endl;
        }
};

class Judge_P   //By Pointer
{
    public :
        User* user_P;
            Computer* computer_P;
        
            Judge_P(User* user_P, Computer* computer_P) : user_P(user_P), computer_P(computer_P) {};
        
        void doJudge()
        {
            std::cout << "User CHOSE hand in class Judge_P := " << user_P->hand << std::endl;
            std::cout << "Computer CHOSE hand in class Judge_P := " << computer_P->hand << std::endl;

        }
};

class Judge_V   //By Value
{
    public :
        void doJudge(int const user_hand, int const computer_hand)
        {
            std::cout << "User CHOSE hand in class Judge_V := " << user_hand << std::endl;
            std::cout << "Computer CHOSE hand in class Judge_V := " << computer_hand << std::endl;
        }
};

int main()
{
    User user;
    user.setHand();
    //std::cout << " user.hand in main() := " << user.hand << std::endl;

    Computer computer;
    computer.setHand();
    //std::cout << " computer.hand in main() := " << computer.hand << std::endl;

    //By Reference
    Judge_R judge_R(user, computer);
    judge_R.doJudge();
    
    //By Pointer
    Judge_P judge_P(&user, &computer);
    judge_P.doJudge();
    
    //By value
    Judge_V judge_V;
    judge_V.doJudge(user.hand, computer.hand);
}

C:\RPS>g++ -o rps.exe rps.cpp

C:\RPS>rps.exe
What you choose? (ROCK = 1, SCISSORS = 2, PAPER = 3) := 1
Computer choose := 2
User CHOSE hand in class Judge_R := 1
Computer CHOSE hand in class Judge_R := 2
User CHOSE hand in class Judge_P := 1
Computer CHOSE hand in class Judge_P := 2
User CHOSE hand in class Judge_V := 1
Computer CHOSE hand in class Judge_V := 2

Upvotes: 0

tbxfreeware
tbxfreeware

Reputation: 2206

How to get member variable from another class in C++

Suppose you have function f, and you want function f to be able to use variables that are defined outside of f. There are a number of different ways to accomplish this, but the simplest is to pass the variables you want to use as arguments to function f.

In this question, for example, function Judge::doJudge needs to use variables that are defined as public members of classes User and Computer.

On the receiving end, define two parameters, user_hand and computer_hand, to receive the arguments.

void doJudge(int const user_hand, int const computer_hand)
{
    std::cout << "User CHOSE hand in class Judge := " << user_hand << std::endl;
    std::cout << "Computer CHOSE hand in class Judge := " << computer_hand << std::endl;

}

On the call side, in function main, pass in the arguments you want to use.

int main()
{
    srand(time(NULL));

    User user;
    user.setHand();

    Computer computer;
    computer.setHand();

    Judge judge;
    judge.doJudge(user.hand, computer.hand);  // Pass in arguments
}

Output from a sample run

What you choose? (ROCK = 1, SCISSORS = 2, PAPER = 3) := 2
Computer choose := 3
User CHOSE hand in class Judge := 2
Computer CHOSE hand in class Judge := 3

Notes

This appears to be some sort of homework assignment, so I am not sure what the problem specification says about class Judge. The problem spec may require that class Judge be used. With the design above, however, you could eliminate class Judge completely, and just keep function doJudge as a stand-alone, free function.

Otherwise, you should delete the member variables user and computer that are defined in class Judge, and declare member function doJudge as const.

As things stand now, all of the constructor functions are empty. They do nothing. If you wanted, you could erase them, which would would cause the compiler to provide compiler-supplied, default constructor functions. Those, too, would do nothing.

With those changes, class Judge would look like this:

class Judge
{
public:
    void doJudge(int const user_hand, int const computer_hand) const
    {
        std::cout << "User CHOSE hand in class Judge := " << user_hand << std::endl;
        std::cout << "Computer CHOSE hand in class Judge := " << computer_hand << std::endl;
    }
};

rand() Considered Harmful

In a video from 2013, Stephan T. Lavavej explains why you should avoid std::rand: rand() Considered Harmful.

Your function random can be replaced by the function below. It seeds the random number generator only once, on the first call to the function.

int random(int const low, int const high)
{
    static std::mt19937 mt{ std::random_device{}() };
    static std::uniform_int_distribution<int> random_number;
    using param_type = std::uniform_int_distribution<int>::param_type;
    return random_number(mt, param_type{ low, high });
}

Notes

std::mt19937 is a Mersenne Twister random number engine from header <random>.

std::random_device, also from header <random>, is a system-dependent way to generate random, unsigned, 32-bit values. Depending on the system, the values can be either pseudo-random quantities or truly random quantities. It is used above to seed std::mt19937, where the initializer is std::random_device{}(). This instantiates a temporary object of type random_device, and then invokes its "call" operator(), to generate a 32-bit seed.

std::uniform_int_distribution is a random number distribution from header <random>. As its name suggests, it generates uniformly distributed integers using the random bits it gets from a random number engine. When instantiated with type int, e.g. std::uniform_int_distribution<int>, its "call" operator() returns a random integer of type int.

param_type is the type used by std::uniform_int_distribution<int> to specify the range of values from which random integers are drawn. param_type{ low, high } is the closed interval [low, high].

When a "local" variable of a function is declared to be static, it is allocated and initialized only once. This happens on the first invocation of the function. Once allocated, the lifetime of a static variable extends until the end of the program. It holds its value between calls to the function.

In function random_integer (above), static variable mt is seeded only once, during its construction, using std::random_device.

Similarly, static variable random_number is initialized only once, by its default constructor.

The return statement invokes the call operator of object random_number, passing in the random number engine mt and a param_type object that specifies the range.

A complete program

When you prefix names from the C++ Standard Library with std::, it is not necessary to have using namespace std; in your program. In production work, most professional programmers avoid using namesapce std;, so you should consider eliminating it here.

// main.cpp
#include <iostream>
#include <random>

int random(int const low, int const high)
{
    static std::mt19937 mt{ std::random_device{}() };
    static std::uniform_int_distribution<int> random_number;
    using param_type = std::uniform_int_distribution<int>::param_type;
    return random_number(mt, param_type{ low, high });
}

class User
{
public:
    int hand;
    void setHand()
    {
        std::cout << "What you choose? (ROCK = 1, SCISSORS = 2, PAPER = 3) := ";
        std::cin >> hand;
    }
};

class Computer
{
public:
    int hand;
    void setHand()
    {
        hand = random(1, 3);
        std::cout << "Computer choose := " << hand << std::endl;
    }
};

class Judge
{
public:
    void doJudge(int const user_hand, int const computer_hand) const
    {
        std::cout << "User CHOSE hand in class Judge := " << user_hand << std::endl;
        std::cout << "Computer CHOSE hand in class Judge := " << computer_hand << std::endl;
    }
};

int main()
{
    User user;
    user.setHand();

    Computer computer;
    computer.setHand();

    Judge judge;
    judge.doJudge(user.hand, computer.hand);
}
// end file: main.cpp

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 598114

The user and computer variables inside of main() are different than the user and computer members inside of the Judge class. You are populating the former, but then acting on the latter.

To do what you are attempting, you should get rid of the variables inside of Judge, and instead pass them into doJudge() as parameters, eg:

class Judge
{
    public :
        Judge(){}; //constructor

        void doJudge(const User &user, const Computer &computer)
        {
            std::cout << "User CHOSE hand in class Judge := " << user.hand << std::endl;
            std::cout << "Computer CHOSE hand in class Judge := " << computer.hand << std::endl;
        }
};

int main()
{
    srand(time(NULL));

    User user;
    user.setHand();

    Computer computer;
    computer.setHand();

    Judge judge;
    judge.doJudge(user, computer);
}

Or, you should make the variables inside of Judge point/refer to the variables inside of main(), eg:

class Judge
{
    public :
        User& user;
        Computer& computer;
        
        Judge(User& user, Computer& computer) : user(user), computer(computer) {};

        void doJudge()
        {
            std::cout << "User CHOSE hand in class Judge := " << user.hand << std::endl;
            std::cout << "Computer CHOSE hand in class Judge := " << computer.hand << std::endl;
        }
};

int main()
{
    srand(time(NULL));

    User user;
    user.setHand();

    Computer computer;
    computer.setHand();

    Judge judge(user, computer);
    judge.doJudge();
}

Upvotes: 2

Related Questions