0

I'm running into a situation where I need to use virtual get and set functions to access members of derived classes. However, as pointed out in the answers of this topic (which is quite similar to my problem by the way), this is a bad practice and may mean that my classes need to be redesigned. The thing is... I'm new to C++ and OOP in general, so I'm not sure how exactly I can write my code in a different way.

If you have the patience, I'll explain my situation: I'm working on a code that can solve two different types of problem (say ProblemX and ProblemY). Depending on the user input, you can solve only problemX, only ProblemY, or both at the same time. If you want to solve only ProblemX, you need only a variable named "memberX". If you want to solve only ProblemY, you need only "memberY". If you want to solve both at the same time, you'll need both "memberX" and "memberY", but the problems will depend on each other, so you can't solve each problem individually. In short, the code would be something like this:

#include <vector>

class Problem
{
public:
    double memberX;
    double memberY;
};

class MainProblem
{
public:
    std::vector<Problem*> problems;
};

int main()
{
    bool solveProblemX = true; // This variable will depend on user input
    bool solveProblemY = true; // This variable will depend on user input
    
    MainProblem * mainProblem = new MainProblem();
    for (int i = 0; i < 10000; i++)
    {
        Problem * problem = new Problem();
        mainProblem->problems.push_back(*problem);
    }
    
    if (solveProblemX && solveProblemY)
    {
        // Solve interconnected problem, using "mainProblem->problem[i]->memberX" and "mainProblem->problem[i]->memberY";
    }
    else if (solveProblemX)
    {
        // Solve individual problem, using only "mainProblem->problem[i]->memberX";
    }   
    else if (solveProblemY)
    {
        // Solve individual problem, using only "mainProblem->problem[i]->memberY";
    }
    else
    {
        // throw some exception
    }
}

So far so good... the real problem is: although I gave only a small sample of the code, my real program is in fact very memory expensive (I actually have a large set of Problems, and each contains a large set of members). So, in order to reduce memory usage, I had to make some modifications. For example: If the user chooses to solve only problemX, the variable memberY will only be a dead weight, since the program won't need it. And vice versa.

Therefore, I thought in making derived classes for ProblemX and ProblemY individually, each containing their respectives data member. That way, I can assign to the vector of problems only a minor class containing specifically the data I need. And if I need both, I use another derived class named ProblemXandY, which containd both memberX and memberY. This is the code I thought:

#include <vector>

class Problem
{
public:
    virtual double getMemberX(){ // Throw some exception};
    virtual double getMemberY(){ // Throw some exception};
};

class ProblemX : public Problem
{
private:
    double memberX;
public:
    double getMemberX(){ return memberX; };
};

class ProblemY : public Problem
{
private:
    double memberY;
public:
    double getMemberY(){ return memberY; };
};

class ProblemXandY : public ProblemX, public ProblemY
{};

class MainProblem
{
public:
    std::vector<Problem*> problems;
};

int main()
{
    bool solveProblemX = true; // This variable will depend on user input
    bool solveProblemY = true; // This variable will depend on user input
    
    MainProblem * mainProblem = new MainProblem();
    for (int i = 0; i < 10000; i++)
    {
        Problem * problem;
        
        if (solveProblemX && solveProblemY)
            problem = new ProblemXandY();
        else if (solveProblemX)
            problem = new ProblemX();
        else if (solveProblemY)
            problem = new ProblemY();
        else
            // throw some exception
        
        mainProblem->problems.push_back(*problem);
    }
    
    if (solveProblemX && solveProblemY)
    {
        for (int i = 0; i < 10000; i++)
        {
            double memberX = mainProblem->problems[i]->getMemberX();
            double memberY = mainProblem->problems[i]->getMemberY();
            // Solve interconnected problem, using "memberX" and "memberY"
        }
    }
    else if (solveProblemX)
    {
        for (int i = 0; i < 10000; i++)
        {
            double memberX = mainProblem->problems[i]->getMemberX();
            // Solve individual problem, using only "memberX";
        }
    }   
    else if (solveProblemY)
    {
        for (int i = 0; i < 10000; i++)
        {
            double memberY = mainProblem->problems[i]->getMemberY();
            // Solve individual problem, using only "memberY";
        }
    }
    else
    {
        // throw some exception
    }
}

My question is regarding the virtual get functions on the class Problem. It feels strange, I agree, since the variables memberX and memberY don't belong to the class Problem. However, without it I wouldn't be able to call mainProblem->problems[i]->getMemberX(), since mainProblem->problems[i] is an object of the base class Problem, instead of the derived classes. As I said, my program is memory expensive. That's why I chose to have a single vector of Problems in the class MainProblem, instead of multiple vectors, one for each derived class. Is there something wrong with my structure here? Should I really redesign it? If so, can you think of an alternative?

  • I don't get why `memberX` and `memberY` need to be exposed. Maybe more pseudo code for using them? – Louis Go Sep 01 '20 at 01:21
  • Also what does `Problem` do except storing `memberX` and `memberY`? If `Problem` is used for storing object, then you just need a container rather than a derived `Problem`, – Louis Go Sep 01 '20 at 01:24
  • 1
    With current context, I'll suggest a pure virtual funciton `Solve` for `Problem`. Unless `member` must be exposed. – Louis Go Sep 01 '20 at 01:32
  • @LouisGo Sorry, I don't understand what you mean by 'exposed'. Is it because the members are public in the first code? That was a mistake... `memberX` and `memberY` are actually private members with get and set functions, as I put in the second code. Also, in the real code, `Problem` does way more than storing `memberX` and `memberY`, so I need to keep that structure. – Pericles Carvalho Sep 01 '20 at 01:46
  • @LouisGo Oh, I see... You mean to eliminate the get functions and access the members only inside the class methods? That won't work in my case... the members need to be exposed because they are what I want to solve... they are the 'Output' of my code. – Pericles Carvalho Sep 01 '20 at 01:56
  • By means of exposing, `getMemberY` function is exposing `memberX` because it's a public function. Your context is not clear about exposing `member` and how to "solve" it. – Louis Go Sep 01 '20 at 02:10
  • 1
    I don't see the point of having a private member instance and then, right next to it, declare a getter for it. A better approach would be to declare those variables as const and simple structs would suffice. There would be no need for getters. – emegona Sep 01 '20 at 02:28

0 Answers0