What is the best way to manipulate objects within other objects?

Hello, I have an object of class BankAccount which has an object of class Person, which has an object of class Date. Here is a simple version of what I have.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  class Date
  {
  private:
    int day;
    int month;
    int year;

  public:
    Date() : day(0), month(0), year(0){} //Default constructor
    void setDate(int x, int y , int z)   //Mutator function
  };

  class Person
  {
  private:
    string firstName;
    string lastName;
    Date birthday;

  public:
    //Constructors go here            
    void setBirthday(int x, int y, int z)    //Function which calls the mutator
  };                                         //function from class Date

  class BankAccount
  {
  private:
    int balance;
    Person bankMember;
  
  public:
    //Constructors go here
    void setMemberBday(int x, int y, int z); //Function which calls the 
  };                                         //function in class Person, which
                                             //calls the mutator of class Date 
  


So I pretty much create functions which call functions which call mutator functions. This repetitiveness makes me think I'm going about it the wrong way. Imaging if I wanted to create another class that includes a BankAccount object. I would end up having more member functions than I can count. The only other way I can think about doing it would be to set the Person member variable of the BankAccount class to public. But my textbook says member variables should almost always be private.
Hello Kevin,
that is a very interesting question. I have two answers for you.

1) When thinking in databases, one person can have 0,1 or more band accounts. So the class BankAccount
can not have a member variable Person bankMember. Otherwise, for more than one bank account, it result
in duplicate and redundant data.
In terms of databases, the bank account should have a personID. The code would look like this:
persons[bankaccont1.personID].firstName;
persons[bankaccont2.personID].firstName;

2) Over the years I created my own design philosophy: "Create once, never change." It is not the OO like thinking from school with all the setter/getter functions. It is OO without setter.

The name and birth date of a person never change, once you created it.
(Okay, okay they does change. But how often in your life do you change your name or birth date? Almost never. )
So, create and access an object should be simple, change it data should be hard.
Same for bank accounts. Create a bank account with one person. But the owner of a bank account does not change.
You would create a new bank account and transfer the money...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <string>
#include <vector>

class Date {
    struct Data {
        int day;
        int month;
        int year;
    };

    Data d;

public:
    Date(int day, int month, int year)
        : d{day, month, year}
    {

    }

    int day() const {
        return d.day;
    }

    int month() const {
        return d.month;
    }

    int year() const {
        return d.year;
    }

    Data& change() {
        return d;
    }
};

class Person {
    struct Data {
        std::string firstName;
        std::string lastName;
        Date birthday;
    };

    Data d;

public:
    Person(std::string firstName, std::string lastName, Date birthday)
        : d{firstName, lastName, birthday}
    {

    }

    std::string firstName() const {
        return d.firstName;
    }

    std::string lastName() const {
        return d.lastName;
    }

    Date birthday() const {
        return d.birthday;
    }

    Data& change() {
        return d;
    }
};

int main() {
    // easy to create the datum
    Person person("Thomas", "Huxhorn", Date{19,04,1984});
    // easy to access the datum
    std::cout << person.firstName() << " " << person.birthday().day();
    // hard the change
    person.change().birthday.change().day = 18;

    // person.birthday().day() = 18; // does not compile
}
The name and birth date of a person never change, once you created it.

not in the real world, lol.
IRL the data entry person typos, the person calls back to complain, and the service person has to fix it. I recommend only locking true constants behind a no-can-touch wall. Names in particular are subject to marriage changes.

Bank account owners can change too; Mine was transferred from my parents to me when I became 16 or so. (My primary account is as old as I am, as an odd side note).

I get that its school work, but you will have to deal with all this junk when you get a job.

The never change design has merits for some code. Just be cautious with any assumptions you are making. I can't even begin to count the tools I have tried to use where I wanted to know something that the tool clearly has internally but denied access to it (usually, hardware). I had to get a screen capture and do OCR on it to get a value from a device once, and have had to pointer hack into any number of others (that one, I never was able to find it with a pointer). You should not have to hack your tools to get what you need from them.

As far as this project, lets step back. Before you design it, lets ask some questions.
what are your requirements? ]
what do you want to DO with bank account class? What do you need to DO with a person?
your design must make DOING the things your program needs to accomplish easier, not harder, and it must be open enough to add more functionality later which will have unknown requirements, so your design must lock out as few paths forward as possible.

as far as getters and setters, I have never embraced this. If you can get it and set it with a function, it may as well be public, *unless that function does something more like validation or logic*. If any variable has a getter/setter, I will put one on everything for consistency but still make the others public to give the user the option. I also bow to the wishes of my employer, some of which demand the getter/setter idea and some don't care. I understand the design principle, but its just code bloat to me 99% of the time and I hate code bloat more than I care about design theory.

From the sound of it you need some sort of inheritance. But what type and what details are key here, and to get that, you need to think about what you want to DO.
Last edited on
Topic archived. No new replies allowed.