Class Questions

Pages: 1234
I'm still learning so it's a fact that there's a lot I don't know, but if member access functions break encapsulation, and the only way to access private members of a class is to use them, then how can we possibly maintain encapsulation?
Use them inside class itself and provide a way to manipuate class state via class member functions.
I'm getting mixed messages. MiiNiPaa, are you saying that getter/setter methods do not break encapsulation?
Last edited on
There is a difference between getter/setter functions and normal member functions that happen to modify member functions. Sometimes it's just a different name but the idea is that you tell classes what to do from the outside, not how to do it. You define their functions as tasks they can do, rather than using them to manipulate the internals of the class manually.
I'm not sure what you mean in your last two sentences, but I do know the difference between member access functions (Getters/Setters) and other member functions that manipulate the class data.

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
#include <iostream>

using namespace std;

class Foo
{
    private:
        int num;

    public:
        // Getter           //
        int getNum()        //
        {                   //
            return num;     //
        }                   //
                            // Access Functions
        // Setter           //
        void setNum(int n)  //
        {                   //
            num = n;        //
        }                   //////
        
        // Manipulates data
        void incrementNum() //
        {                   // Ordinary Public Member Function
            ++num;          //
        }                   //////
};

int main()
{
    Foo a;

    a.setNum(1);
    cout << a.getNum();

    a.incrementNum();

    return 0;
}

Edit:
I suppose the question is, do Getter/Setter functions like this break encapsulation?
Last edited on
do Getter/Setter functions like this break encapsulation?
If they are here just for sake of giving access to member, then yes. I they are happened to give access to the variable as part of class interface, then no.

Does vector operator[] break encapsulation? It gives access to variable in internal array. The answer is no, it doesn't: vector is designed to be a container and give access to contained values.

Would ability to directly access and modify internal pointer to the buffer break encapsulation? Yes, it would: it is part of implementation which is insignificant for the vector interface and design. Also it could break vector completely: it usually contains several other pointers which should be changed in sync with buffer pointer. So vector manages these pointers itself and does not expose them.
Would you please show me an example of how to work with private class variables and functions without breaking encapsulation? This is something I'm struggling to understand.
The trick is to design interface first without thinking about member variables, then implement it. Design what, not how.
For example we need a class representing a videogame in store. What do we need from it? We need to be able to know its title, rating and price. Imagine that Rating is already existing class. So we have:
1
2
3
4
5
6
7
class Game
{
  public:
    std::string title() const;
    Rating rating() const;
    double price() const;
};
Notice that we only have functions, not variables in class. In fact, I did not even consider how I would implement it.
Lets take a look: for title it is enough to just have a string inside our class. Same for rating: we will just store Rating object inside out class.
Price is calculated depending on game category (how popular game is) and if it is preorder (which cost more). So we will store game category and release date inside our class so we would be able to calculate price.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Game
{
  public:
    std::string title() const;
    Rating rating() const;
    double price() const;
    enum category { AAA, popular, obscure, outdated };
  private:
    std::string title_;
    Rating ESRB;
    category cat;
    std::tm release_date;
};
So we have 3 member functions 2 of which are simple getters. But those getters do not break encapsulation. They were intended to do what they do from the very beginning. It just happened that the most direct way of implementing them was to make them getters
Thank you for your efforts MiiNiPaa, but I'm still confused.

If you're still returning the values of the private members through public member functions, how is that different from using Getters?

You say to focus on designing the interface first, but that's hard to get my head around. How can you know how your class will work before you try to implement the details?

I apologise if my inability to clearly grasp what you're trying to explain to me has you frustrated. It certainly has me frustrated.

You wouldn't happen to know of somewhere that provides beginner friendly class exercises that gradually build on new concepts, would you? I've looked around, but haven't been able to find any.
The idea is difficult to get your head around but it is fundamental. Work out what you want to make and what it will do and what functions it will need to do before you make it. If you are making a dog class, it might need functions like feed() and walk(). Feed could just increase a variable named weight or health, but that doesn't matter yet. You need to work out what functionality your class will have to have, and, if needs be, write the function declarations to start with, then you add member variables as you need them and implementation of functions as you can. The idea of OOP is that the class you are making is of an actual thing, not a collection of data. That's a struct.
Thanks shadowmouse, that makes sense. Hopefully it will start to feel like the natural thing to do the more I practice. To someone who has spent almost all of the last year learning programming in C, OOP is an alien concept.

Do you know of anywhere that has a good amount of beginner class exercises?
1
2
3
4
void setVal(int number)
{
    this->number = number;
}

In this class member function, is this type of expression at line 3 the equivalent to saying "assign the contents at the address of the class member variable the value of the parameter variable"?

Is this a special kind of pointer that points to class variables automatically, without being explicitly told to?

Is the this keyword used primarily to differentiate between member variables and parameter variables of the same name?

Does the this keyword have any uses or applications outside of a class?
Is this a special kind of pointer that points to class variables automatically, without being explicitly told to?
It is an expression which evaluates to the address of current object. It does not truly exist as member and does not take any space.

Is the this keyword used primarily to differentiate between member variables and parameter variables of the same name?
Yes, it is mainly used to show that we are really manipulating class member.

Does the this keyword have any uses or applications outside of a class?
No
That example you showed is one of the main reasons for prefixing all member variables (especially private ones) with m_. It means you don't have to use this-> (there's usually no need) and you can have sensible parameter names.
I see. And am I correct in how I think this expression works (line in quotes)?
Not exactly. this is a pointer to the object which calls it. -> means function/variable of the object that is pointed to and the rest is simple. So in summary:
1
2
3
4
5
this //pointer to self
->  //access member of object pointed to
number  //member to access
= //Assign the value of the next line to the previous
number; //The variable named number declared as a parameter 
Last edited on
Generally, is it preferred or better to create two constructors like this:
1
2
3
4
5
6
Person()
{
    name = "Name";
}

Person(string n) : name(n) {}

or one constructor like this:
 
Person(string n = "Name") : name(n) {}

The end result is the same, a default value and a user provided value are handled, but the first way requires you to have two constructors. Is one way better or does it matter?
It does not actually matters, but first one is better written as:

Person() : name("Name") {}
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
#include <iostream>
#include <string>

using namespace std;

class DateOfBirth
{
    public:
        DateOfBirth(int d = 1, int m = 1, int y = 1)
        : day(d), month(m), year(y)
        {}

        void getDOB()
        {
            cout << day << "/" << month << "/" << year;
        }

    private:
        int day;
        int month;
        int year;
};

class Person
{
    public:
        Person(string n = "Name") : name(n) {}

        string getName()
        {
            return name;
        }

        DateOfBirth DOB;

    private:
        string name;
};

int main()
{
    Person person1;

    cout << person1.getName() << "'s date of birth is ";
    person1.DOB.getDOB();

    return 0;
}

I'm testing out composition and I'd like to know a few things.

Am I implementing composition correctly, or is there a better way?

Is it possible to provide values to the private members of the class DateOfBirth upon instantiation of the object person1? I thought it would make sense to give a person a date of birth upon creation. I could create a setter function to do this but a person shouldn't have the ability to set their date of birth at a later point. Something I tried was this:
 
Person person1.DOB(2, 2, 2);
but I got an error.

When should objects of composed classes, like DOB, be made public and when should they be made private?
Create a constructor which will initialize DOB too. Examples:

1
2
Person(std::string n = "Name", DateOfBirth d) : name(n), DOB(d) {}
Person(std::string n = "Name", int d = 1, int m = 1, int y = 1) : name(n), DOB(d, m, y) {}
Pages: 1234