Class Questions

Pages: 1234
I've just started trying to learn classes in C++.

In the code below, I've created a constructor for the class drink which initialises the variables name and price. Why am I able to assign default values to these variables when they have not yet been declared in the code, at the point of assignment?

Secondly, when creating the object coke of type drink, I am able to declare it with and without explicitly specifying that it is the object of a class, for example:
 
class drink coke;

...And...
 
drink coke;


Is there any difference between declaring objects one way or the other? Is one way more widely accepted or traditionally used?

Is it better to create a constructor as a private or public member function? Is it even considered a member function? If there is a preference or more approved way, why?

These are all the questions I have so far. I will use this thread to ask more questions as I continue to learn more about classes, if that is acceptable. Any help you can provide is much appreciated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

using namespace std;

class drink
{
    public:
        drink()
        {
            name = "Coke";
            price = 1.99;
        }

        string name;
        double price;
};

int main()
{
    drink coke;

    cout << coke.name << coke.price;
}
Why am I able to assign default values to these variables when they have not yet been declared in the code, at the point of assignment?
Classes are special case. All class member are able to interact with member variables even if they are defined later in code.

Is there any difference between declaring objects one way or the other? Is one way more widely accepted or traditionally used?
No. In C++ it is preferably to drop explicit class/struct mention.

Is it better to create a constructor as a private or public member function?
Usually you want your constructor to be public to be able to construct your class. However there are a bunch of reasons why you might want your constructors or some of them to be private (singleton is one example).

Is it even considered a member function?
Yes. It is a special specific member function. (special member function is a term in Standard with another meaning. Default constructor is, however, a special function)

If there is a preference or more approved way, why?
As I said before, it depends on what you need.
Last edited on
Thank you MiiNiPaa. I'll be back when I have more questions.
When using classes, is it more common to incorporate inheritance, with an overarching generic base class and layers of (possibly branching) derived classes, or to use one big class to contain every little bit of possible data and functionality you might need?

Just from writing this question down I can sense that it is most probably the former due to logical modularity, but I'll ask anyway just to be sure.

In the code below I am trying to access the public member function attack() but the compiler seems to think I am trying to access the private member variable attack and gives me an error. I would have thought the parentheses were enough to distinguish between the two. Is the only way to get around this problem to change the name of either attack or attack()?

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

using namespace std;

class Player
{
    private:
        int health;
        int mana;
        int attack;
        int defense;
        int speed;

    public:
        Player()
        {
            health = 0;
            mana = 0;
            attack = 0;
            defense = 0;
            speed = 0;
        }
        
        void attack()
        {
            cout << "You attack!" << endl;
        }

        void defend()
        {
            cout << "You defend!" << endl;
        }
};

int main()
{
    Player player1;

    player1.attack();

    return 0;
}

1) It is really depends on your need, but it is better to avoid excees and too deep inheritance. One thing you should remember is to prefer composition to inheritance.
https://en.wikipedia.org/wiki/Composition_over_inheritance
http://www.artima.com/cppsource/codestandards3.html

For example you can have a Mob class which has health, attack, etc. Then you need to create another kind of mob which can attack at a distance. One way will be to create a subclass called RangedMob and do work here, but in fact you should consider just giving a Mob a member called attack_type. It might be a simple enumeration value at first, transforming in fullfledged class with own behavior later.

2) In your case problem is encountered earlier: you have two members called attack. It does not matter that they are of different types, they have the same name. And you cannot have two entities with same name declared in same scope.

Error log for my compiler:
||=== Build: Debug in Test (compiler: GNU GCC 4.9.1x64) ===|
\Test\main.cpp|55|error: 'void Player::attack()' conflicts with a previous declaration|
\Test\main.cpp|38|note: previous declaration 'int Player::attack'|
\Test\main.cpp||In constructor 'Player::Player()':|
\Test\main.cpp|47|error: invalid use of member (did you forget the '&' ?)|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 3 second(s)) ===|
http://ideone.com/3q3L5R



Is there any reason to use a member initialisation list in a constructor, other than to initialise const member variables, over initialising the values normally inside the body of the constructor?

Is the : in a member initialisation list context referred to as the member initialisation operator?
Is there any reason to use a member initialisation list in a constructor
there is no reasons to not to.
When you don't, you are first creating default initialized members incurring construction cost, and then copy-assign new value to it, incurring assigment cost.
With member init list, you just creating them in-place. No additional overhead after creation.

Is the : in a member initialisation list context referred to as the member initialisation operator?
No, there is no member initialisation operator in C++. It this context : merely denotes start of init list.
So as a general rule, should you always use initialisation lists wherever possible?
Yes. That is how you should do it.
Should the class access specifiers be indented or not? I'm wondering because when using Code::Blocks the access specifiers are automatically unindented.

Is this the proper way to set up a class and use member initialisation when using multiple files?

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include "Test.h"

using namespace std;

int main()
{
    Test object(10);

    cout << object.getVal();

    return 0;
}

Test.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "Test.h"

using namespace std;

Test::Test(int x) : val(x) {}

int Test::getVal()
{
    return val;
}

Test.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef TEST_H
#define TEST_H

class Test
{
    private:
        int val;

    public:
        Test(int x);

        int getVal();
};

#endif 

In Test.h I include only the class definition with the member variable and the function declarations. I leave the function definitions to Test.cpp, as I believe is correct.
Last edited on
Is this the proper way to set up a class and use member initialisation when using multiple files?
Yes. It is a proper way.

Should the class access specifiers be indented or not?
There are many indentation rules and there is no one which everyone adhere. Use what you like, or what is used in project you are working on.
When working on anything serious, is it better to set up your project across multiple files rather than keeping everything together in one file?
Yes, it is good to separate group of entities related to single responsibility to their own file/files.
It increases maintainability and allows for more efficient code reuse.
Thanks MiiNiPaa. I hope I'm not annoying you with all these questions. I do appreciate your help.
As far as I understand, making class members private is to stop objects of that class from directly accessing them. To access the data, public access functions (Getters and Setters) are used instead. Considering the fact that objects of a class cannot access members of another class anyway, regardless of access level, why is this done? Shouldn't objects be able to freely access and utilise their own properties and functionalities?
Considering the fact that objects of a class cannot access members of another class anyway, regardless of access level
They can:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class foo
{
    public:
        int i;
};

class bar
{
    public:
        void accept(foo& f)
        {
            f.i = 10; //Changing member of passed object;
        }
};

int main()
{
    foo x;
    x.i = 5; //Changing member of class
    bar b;
    b.accept(x); // Changing member by another class.
};
Shouldn't objects be able to freely access and utilise their own properties and functionalities?
Emphasis mine. They sure should, but their own members only.
If I understand that right, you are referencing the object x of class foo and assigning it's member variable i a new value in the public function of class bar.

Okay, so is passing objects of one class to another class, by reference, via public member functions, the only way to access and potentially modify public member variables and functions of other class objects?

What reasons could there be to do such a thing?
What reasons could there be to do such a thing?
...you need to change that object? That is the reasong why passing by reference exist in C++.
When you are overloading IO operators you usually need to take stream by reference and change it by calling another operator.
No, what I mean is, since encapsulation is pretty much essential to OOP, is there any reason you might want to access the public members of a class object from a different class object? I wouldn't think there are any reasons, and that if it happens, it's because a mistake was made.

Instead, If you wanted to access the members of another class, composition would be the correct technique to use, wouldn't it?
Encapsulation may be a fundamental part of OOP, but there is no reason for it to be forced on all programmers. It is possible that a programmer could use a public member variable and it might not be bad design, it could be done via getter/setter methods but many people say these break encapsulation. Composition is the correct method if one class contains another. I'm pretty sure composition doesn't change this anyway because access specifiers still apply when objects are composed of other objects. Especially with simple things, it is often unnecessary to fully encapsulate simple, small classes.
Pages: 1234