Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a class member that is automatically calculated from other class members?

Tags:

c++

class

  1. I'm an absolute newbee when it comes to programming and I'm trying to teach myself the basics by just solving some easy "problems" in C++.

  2. I have searched the web for an exact answer to my question before posting it here and haven't found one so far, however that may be because of (1).

So, what I'm looking for is a way to declare a class member that gets automatically calculated from other members of the same class, so that the calculated class member can be used just like an explicitly defined class member would. For example imagine a struct called creature that has the properties/members creature.numberofhands, creature.fingersperhand and finally the property creature.totalfingers that automatically gets calculated from the above members.

Heres an example of the closest I got to what I wanted to achieve:

#include <iostream>

typedef struct creature {
    int numberofhands;
    int fingersperhand;
    int totalfingers();
} creature;    

int creature::totalfingers()
{
    return numberofhands * fingersperhand;
};

int main()
{
    creature human;
    human.numberofhands = 2;
    human.fingersperhand = 5;

    printf("%d",human.totalfingers());
    return(0);
}

What's really annoying me about this, is that I have to treat the calculated one DIFFERENTLY from the explicitly defined ones, i.e. I have to put "()" after it. How can I change the code, so I can use: human.totalfingers without ever explicitly defining it?

like image 665
TrveBlack Avatar asked Dec 23 '22 16:12

TrveBlack


1 Answers

The simplest option would be to use public member functions and make the actual properties hidden. Something like this:

class Creature {
public:
    Creature(int numhands, int fingersperhand) // constructor
        : m_numhands{numhands}, m_fingersperhand{fingersperhand}
        { }
    int fingersPerHand() const { return m_fingersperhand; }
    int numberOfHands() const { return m_numhands; }
    int totalFingers() const { return numberOfHands() * fingersPerHand(); }

private:
    const int m_numhands;
    const int m_fingersperhand;
};

The private member variables are an implementation detail. Users of the class just use the three public member functions to get the different number of fingers after construction and don't need to care that two of them are returning constant stored numbers and the third returns a calculated value - that's irrelevant to users.

An example of use:

#include <iostream>
int main()
{
    Creature human{2, 5};
    std::cout << "A human has "
        << human.totalFingers() << " fingers. "
        << human.fingersPerHand() << " on each of their "
        << human.numberOfHands() << " hands.\n";
    return 0;
}

If - as per your comment - you don't want to use a constructor (although that's the safest way to ensure you don't forget to initialize a member), you can modify the class like this:

class CreatureV2 {
public:
    int fingersPerHand() const { return m_fingersperhand; }
    int numberOfHands() const { return m_numhands; }
    int totalFingers() const { return numberOfHands() * fingersPerHand(); }

    void setFingersPerHand(int num) { m_fingersperhand = num; }
    void setNumberOfHands(int num) { m_numhands = num; }

private:
    // Note: these are no longer `const` and I've given them default
    // values matching a human, so if you do nothing you'll get
    // human hands.
    int m_numhands = 2;
    int m_fingersperhand = 5;
};

Example of use of the modified class:

#include <iostream>
int main()
{
    CreatureV2 human;
    std::cout << "A human has "
        << human.totalFingers() << " fingers. "
        << human.fingersPerHand() << " on each of their "
        << human.numberOfHands() << " hands.\n";

    CreatureV2 monster;
    monster.setFingersPerHand(7);
    monster.setNumberOfHands(5);
    std::cout << "A monster has "
        << monster.totalFingers() << " fingers. "
        << monster.fingersPerHand() << " on each of their "
        << monster.numberOfHands() << " hands.\n";

    CreatureV2 freak;
    freak.setFingersPerHand(9);
    // Note: I forgot to specify the number of hands, so a freak get 
    // the default 2.
    std::cout << "A freak has "
        << freak.totalFingers() << " fingers. "
        << freak.fingersPerHand() << " on each of their "
        << freak.numberOfHands() << " hands.\n";

    return 0;
}

Note: all of the above assumes you are using a modern C++14 compiler.

like image 52
Jesper Juhl Avatar answered Jan 12 '23 01:01

Jesper Juhl