Access private variables from class in C++

49,410

Solution 1

A very unpopular option is to use setters and getters.

class A {
  public:
    void set_life(int life) { life_ = life; }
    void set_greeting(std::string greeting) { greeting_ = greeting; }
    int get_life() const { return life_; }
    std::string get_greeting() const { return greeting_; }
  private:
    int life_;
    std::string greeting_;
};

These would be used in the following way:

int main() {
  A a;
  a.set_life(42); // My object's life_ variable is now 42.
  a.set_greeting("Hello, World!"); // My object's greeting_ variable is now "Hello, World!".

  std::cout << a.get_greeting() << " The meaning of life is " << a.get_life() << '\n';
  // "Hello World! The meaning of life is 42
}

This is considered a faux-pas because if you introduce getters and setters as a rule for every private variable, you might as well make the variables public - they can be changed anyway.

A better practice is to use your constructor to set your variables initially and create a method to do what you need with your variables - the programmer shouldn't need to know about them (hence private).

class A {
  public:
    // Construct life_ with life and greeting_ with greeting
    A(int life, std::string greeting) : life_(life), greeting_(greeting) {}
    void print_message() const { 
        std::cout << greeting_ << " The meaning of life is " << life_ << '\n';
    }
  private:
    int life_;
    std::string greeting_;
};   

and now your main would look like this:

int main() {
  A a(42, "Hello, World!");
  a.print_message();
}

Solution 2

As Paul mentioned, if you are making the variables private inside a the Equation class, then you would not want any entity other than the Equation class to have access to those variables.

In this case, you should solve for x and y using private members of the class (since class members can access private variables of the class), and provide a public interface to access the results of solving the system.

For example:

#include <utility>  // For std::pair

class EquationSolver {
public: 
  EquationSolver(int _a, int _b, int _c, int _d, int _e, int _f)
  : a(_a), b(_b), c(_c), d(_d), e(_e), f(_f), x(0.0), y(0.0) {}

  // This is the interface for solving the equations via method a
  // And allows outside entities to get the result of solving the system
  std::pair<double, double> solveViaMethodA() {
    solveForXInternally();  // This solves for X via the private implementation below
    solveForYInternally();  // This solves for Y via the private implementation below

    // x and y have been updated internally, so they can be returned as the result of the solved system
    return std::make_pair(x, y);
  }
private:
  int a, b, c, d, e, f;
  double x, y;

  // This is an implementation for solving for x 
  void solveForXInternally() {
    x = ((c*e)-(b*f))/ ((a*e)-(b*d));
  }
  // This is an implementation for solving for y 
  void solveForYInternally() {
    y = ((a*f)-(c*d))/ ((a*e)-(b*d));
  }
};

Now you can use this class to solve equations as follows:

int main() {
  // Create an instance of the EquationSolver class
  EquationSolver solver(1, 2, 3, 4, 5, 6);

  // Use the instance of the solver to solve the equations
  std::pair<double, double> solved_variables = solver. solveViaMethodA();
}

While this example illustrates using a class to store the coefficients required for solving the equation, it is not necessary for solving a single equation. A far more concise solution would be to use a single function, as follows:

#include <utility>

std::pair<double, double> solveSystem(int a, int b, int c, int d, int e, int f) {
  double x = ((c*e)-(b*f))/ ((a*e)-(b*d));  
  double y = ((a*f)-(c*d))/ ((a*e)-(b*d));
  return std::make_pair(x, y);
};

int main() {
  std::pair<double, double> solved_variables = solveSystem(1, 2, 3, 4, 5, 6);
}

What using a class does allow, however, is for the solution to be easily extended. For example, in the EquationSolver class I provided, if you wanted to solve the equations differently then you could implement additional private member functions to solve for x and y internally, and add another public member function to access the solution via the alternate method.

Solution 3

Of course, understanding how to interact with a class's privates implies grokking the point of private, class, and all, summarized in one term as "encapsulation," a major property provided by OOP.

Object-oriented programming is about objects interacting with each other over interfaces. These interfaces supply users with altering the object's state. In a 3D-context, for example, a cube can be rotated, the coordinates of one of its vertices can be retrieved, etc.
Why interfaces? To hide implementation details. Internal variables (private variables) are not supposed to be visible to any user of the object. OTOH, there are exposed variables (marked public), which depict that interface I was talking about.
For completeness's sake, I'll mention protected, which shares its subordinate variables with derived classes, but that's beside the point of this question, IMO.
But why hide implementation details? To make users independent of the internal structure and state of an object. Any changes there are invisible to users, which improves maintainability, code readability, and code reusability.

So, how to proceed any further? You need to think about how the Equation class will be used and its internal state and its exposures. An equation consists of a multitude of variables. They should be the internal state. It's got two sides (maybe more). You need some way to represent them. Operations on equations: solving them? Performing equivalency transformations? Printing them out? That's what you have to think about.

Note: others have mentioned setters and getters. They are used to set and get member variables of an object, respectively. It's bad because they break encapsulation; they change the state of the object directly, defeating the purpose of OOP except when trying to make mutable member variables appear constant or controlling the modification of variables with customized code, for example.

Solution 4

One of the strongest aspects of Object Oriented Programming is to have encapsulation, i.e. each object handles their own data in their own way. The reason why people suggest to declare variables as private members is to make sure that the class is always in a valid state. Trust your classes. Give them responsibility, the power to handle their own system.

Another main point is the separation of concerns. Basically, if the action you want to take needs an object to change its variables, then let the object handle that action. The way you make this happen is to declare a function in the public section of your class, let your clients (any piece of code that interacts with your class) "request" that class to make a change and make your class handle that change. This is the second step of trusting your classes (I like to call this Empowering your classes). Does something need to be done using your class that changes a data? Let your class do it. Don't let other entities bully your class with their ordering your class around. Make them ask, nay beg for it.

All jokes aside, Getters and Setters are the (arguably) disgusting by-products of this approach. Technically, having those in your class fits in the scheme of Object Oriented Programming, because you are providing an interface for your clients to interact with your data. However, the way it works is against the reason why we have access modifiers in the first place. Practices like that are usually referred to as anti-patterns in computer science, meaning that it is a mutated, dangerous form of a pattern. I personally don't find Getters that bad but Setters are the roots of all sorts of nasty bugs.

RobClucas' answer would be the direction I'd take. But instead of sending the data through the constructor, I'd also carry the input reading functionality into the EquationSolver class. This approach seems more similar to what you were planning to do in the first place and involves less code changing.

Your class would be something like this:

class EquationSolver {
public:
    void GetEquationParameters() {
        /* This is where your while(cin) blocks are
         You are reading information directly into this class' paramters
         while(cin>>a1)
         while(cin>>a2)
         etc..

        See how you're "asking" this class to read data from the user.
         */

        while ((cout << "Enter the value of a1 :\n")
            && !(cin >> a1)) {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }

        while ((cout << "Enter the value of a2 :\n")
            && !(cin >> a2)) {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }

        while ((cout << "Enter the value of b1 :\n")
            && !(cin >> b1)) {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }

        while ((cout << "Enter the value of b2 :\n")
            && !(cin >> b2)) {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }

        while ((cout << "Enter the value of c1 :\n")
            && !(cin >> c1)) {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }

        while ((cout << "Enter the value of c2 :\n")
            && !(cin >> c2)) {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    }

    /*
     * Functions for your client to use to get the final data.
     * Former is the C++ style that returns both values as a pair.
     * Latter is the sweet sweet C style where you fill x and y inside the function.
     * Latter is less data transaction if you care about performance that much.
     */
    std::pair<double, double> SolveEquationSystem() const {
        double x = (b1*c1 - a2*c2) / (a1*c1 - a2*b2);
        double y = (a1*c2 - b1*b2) / (a1*c1 - a2*b2);

        return std::pair<double, double>(x, y);
    }
    void SolveEquationSystem(double * x, double * y) const {
        *x = (b1*c1 - a2*c2) / (a1*c1 - a2*b2);
        *y = (a1*c2 - b1*b2) / (a1*c1 - a2*b2);
    }

    /**
     * Human readable print
     */
    void PrintEquation() {
        cout << "The first equation is : " << a1 << "x" << "+" << b1 << "y" << "=" << c1 << "\n" << endl;
        cout << "The second equation is : " << a2 << "x" << "+" << b2 << "y" << "=" << c2 << "\n" << endl;
    }
private:
    int a1, a2, b1, b2, c1, c2;
};

And in the main function, this is how you use it:

void main() {
    cout << "\n" << endl;
    cout << "                        **** Hello ****               \n\n" << endl;
    cout << "This is a program to solve a system of equation" << endl;
        cout << "Equations will look like a1*x+b1*y=c1" << endl;
    cout << "and  a2*x+b2*y=c2\n" << endl;
    cout << "Enter the values for the first equation \n" << endl;

    // Create solver
    EquationSolver solver;

    // Ask solver to get parameters from the user
    solver.GetEquationParameters();
    // Ask solver to print equation in human readable format
    solver.PrintEquation();

    double x, y;
    // Ask solver to do what it's supposed to do
    solver.SolveEquationSystem(&x, &y);

    cout << "The solution of the system is " << "x = " << x << "\t" << "y = " << y << "\n\n" << endl;
    cout << "                        **** Thank You ****                 " << endl;

}

Check out how I'm interacting with the class. As a client main, I'm asking a class provided to me for actions. I ask it to get parameters that it's going to use, then asking it to solve the system using it's data. This way if there is an error, it's not about the class; it's the way I'm using the class.

Sidenote: try not to use using namespace std. I know that schools teach you to use it but that's just your teachers being lazy. using namespace x includes the entire namespace into the header file and while it's not much of a big deal for small projects, it can cause some serious problems as the scale of the project gets bigger.

If you really want to get rid of std::, say for cout and endl, then you can use using std::cout; and using std::endl; instead of the entire namespace. For non-specific functions though, I still suggest you to use std:: (for example, I'd use it for std::numeric_limits to specify that I'm not the owner, I'm just using it).

Share:
49,410
Admin
Author by

Admin

Updated on June 17, 2021

Comments

  • Admin
    Admin about 3 years

    Im working on a project and I want to declare private variables inside a class because I've read in many places that it's better than declaring them public but how can I access them in main ? What kind of functions should I use to make them accessible ? I want to solve the system through a function not from main as I've done. Thats my code so far,

    #include <iostream>
    #include <limits>
    
    using namespace std;
    
    class Equation
    {
        private:
            int a1, a2, b1, b2, c1, c2;
    
        public:
    };
    
    int main() 
    {
        int a, b, c, d, e, f;
        cout << "\n" << endl;
        cout << "                        **** Hello ****               \n\n" << endl;
        cout << "This is a program to solve a system of equation" << endl;
        cout << "Equations will look like a1*x+b1*y=c1" << endl;
        cout << "and  a2*x+b2*y=c2\n" << endl;
        cout << "Enter the values for the first equation \n" << endl;
    
        while ((cout << "Enter the value of a1 :\n") && !(cin >> a)) 
        {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    
        while ((cout << "Enter the value of a2 :\n") && !(cin >> b)) 
        {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    
        while ((cout << "Enter the value of b1 :\n") && !(cin >> c)) 
        {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    
        while ((cout << "Enter the value of b2 :\n") && !(cin >> d)) 
        {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    
        while ((cout << "Enter the value of c1 :\n") && !(cin >> e)) 
        {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    
        while ((cout << "Enter the value of c2 :\n") && !(cin >> f)) 
        {
            cout << "Invalid input, please enter a number \n" << endl;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    
        cout << "The first equation is : " << a << "x" <<
            "+" << c << "y" <<
            "=" << e << "\n" <<
            endl;
    
        cout << "The second equation is : " << b << "x" <<
            "+" << d << "y" <<
            "=" << f << "\n" <<
            endl;
    
        double x = ((c * e) - (b * f)) / ((a * e) - (b * d));
        double y = ((a * f) - (c * d)) / ((a * e) - (b * d));
    
        cout << "The solution of the system is " <<
            "x = " << x << "\t" <<
            "y = " << y <<
            "\n\n" <<endl;
        cout << "                        **** Thank You ****                 " << endl;
    
        return 0;
    }