Class Questions

Pages: 1234
Jul 4, 2015 at 7:06pm
I tried your recommendations but Person(std::string n = "Name", DateOfBirth d) : name(n), DOB(d) {} will not compile and Person(std::string n = "Name", int d = 1, int m = 1, int y = 1) : name(n), DOB(d, m, y) {} is giving me warnings.
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, int m, int y)
        : day(d), month(m), year(y) {}

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

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

class Person
{
    public:
        Person(string n = "Name", int d = 1, int m = 1, int y = 1)
        : name(n), DOB(d, m, y) {}

        string getName()
        {
            return name;
        }

        DateOfBirth DOB;

    private:
        string name;
};

int main()
{
    Person person1;

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

    return 0;
}

Warnings:

||=== Build: Debug in composition (compiler: GNU GCC Compiler) ===|
F:\Program Files\Programming\C++ Programs\composition\main.cpp||In constructor 'Person::Person(std::string, int, int, int)':|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|37|warning: 'Person::name' will be initialized after [-Wreorder]|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|34|warning:   'DateOfBirth Person::DOB' [-Wreorder]|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|26|warning:   when initialized here [-Wreorder]|
||=== Build finished: 0 error(s), 3 warning(s) (0 minute(s), 0 second(s)) ===|
||=== Run: Debug in composition (compiler: GNU GCC Compiler) ===|

Do you know how to fix these warnings?
Jul 4, 2015 at 7:21pm
Person(std::string n = "Name", DateOfBirth d) : name(n), DOB(d) {} will not compile
Remove default value from n. Or add it to DOB, or swap order of name and dob.

Do you know how to fix these warnings?
Yes, change order of initialization in constructor:
Person(string n = "Name", int d = 1, int m = 1, int y = 1) : DOB(d, m, y), name(n) {}
Jul 4, 2015 at 9:25pm
I can get the second solution to work but not the first. Why does the initialisation order matter?

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, int m, int y)
        : day(d), month(m), year(y) {}

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

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

class Person
{
    public:
        Person(string n = "Name", DateOfBirth d)
        : DOB(d), name(n) {}

        string getName()
        {
            return name;
        }

        DateOfBirth DOB;

    private:
        string name;
};

int main()
{
    Person person1("Person", 2, 3, 4);

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

    return 0;
}


||=== Build: Debug in composition (compiler: GNU GCC Compiler) ===|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|75|error: default argument missing for parameter 2 of 'Person::Person(std::string, DateOfBirth)'|
F:\Program Files\Programming\C++ Programs\composition\main.cpp||In function 'int main()':|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|91|error: no matching function for call to 'Person::Person(const char [7], int, int, int)'|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|91|note: candidates are:|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|75|note: Person::Person(std::string, DateOfBirth)|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|75|note:   candidate expects 2 arguments, 4 provided|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note: Person::Person(const Person&)|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note:   candidate expects 1 argument, 4 provided|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note: Person::Person(Person&&)|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note:   candidate expects 1 argument, 4 provided|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

How can I get this to work?
Jul 4, 2015 at 9:44pm
Initialization order does not actually matter and this is why warning is issued: you might think that order in initialization list matters, but it does not. Members are always initializated in order of their declaration in class. So it is a good idea to have them in same order in initialization list to make sure that there would not any surprises.

About first one:
MiiNiPaa wrote:
Remove default value from n.
Last edited on Jul 4, 2015 at 9:45pm
Jul 4, 2015 at 9:57pm
Thanks for the explanation.

I removed the default value but I'm still getting errors:

||=== Build: Debug in composition (compiler: GNU GCC Compiler) ===|
F:\Program Files\Programming\C++ Programs\composition\main.cpp||In function 'int main()':|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|91|error: no matching function for call to 'Person::Person(const char [5], int, int, int)'|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|91|note: candidates are:|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|75|note: Person::Person(std::string, DateOfBirth)|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|75|note:   candidate expects 2 arguments, 4 provided|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note: Person::Person(const Person&)|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note:   candidate expects 1 argument, 4 provided|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note: Person::Person(Person&&)|
F:\Program Files\Programming\C++ Programs\composition\main.cpp|72|note:   candidate expects 1 argument, 4 provided|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Jul 4, 2015 at 10:03pm
no matching function for call to 'Person::Person(const char [7], int, int, int)'
You are trying to call constructor taking name and 3 ints, but implemented only one taking name and DateOfBirth.
Jul 4, 2015 at 10:08pm
The thing is though, in the call to the constructor I have to supply values for the day, month and year. Supplying three ints is I think unavoidable.
 
Person person1("Person", 2, 3, 4);


EDIT:
Is this the only way to get around the problem?
1
2
DateOfBirth dob(2,2,2);
Person person1("Name", dob);
Last edited on Jul 4, 2015 at 10:12pm
Jul 4, 2015 at 10:38pm
No, you can either create constructor taking 3 ints, or pass a temporary: http://ideone.com/kgvHX5
Jul 5, 2015 at 10:27am
Calling the constructor that way works, but since it's a 'temporary' pass, does that mean the members aren't permanently set to the values you pass?
Jul 5, 2015 at 11:11am
No, they are set. Temporary refers to value you pass: you are creating a temporary object with data you enter, pass it to Person constructor, constructor copies data from passed object to Person member, then passed object is destroyed as it is only temporary. But data is already extracted from it and safely stored, so there is no danger that it will disappear.
Jul 5, 2015 at 11:43am
Okay, thanks for clearing that up. That's a nice technique to know about. Can you pass as many temporary objects as you want?
Jul 5, 2015 at 11:56am
Yes, just be wary about cost of creating and destroying them. Often it is better to take them by const reference instead of by value to mitigate amount of copies. (And sometimes it is better to take it by value and move in place, after you learn move semantics)
Jul 10, 2015 at 7:04pm
Is it good or bad design to set up classes in such a way as to have a base class that you derive other classes from, but never create an object of that base class? For example, you may have a base class called Class to contain generic information, such as names and stats, that all derived classes, such as Warrior or Mage, will use.

With inheritance like this, it wouldn't really make sense to create objects of type Class, but rather it would be better to create objects of the more well defined derived classes, Warrior and Mage.

Is this good or bad design?
Last edited on Jul 10, 2015 at 7:05pm
Jul 10, 2015 at 7:12pm
Sounds like Abstract Base Class (ABC). Which is legitimate design choice.
https://isocpp.org/wiki/faq/abcs
Jul 20, 2015 at 7:20pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

class MyClass
{
    public:
        void print()
        {
            cout << "Hello." << endl;
        }
};

int main()
{
    MyClass *pointer = new MyClass();

    pointer->print();

    return 0;
}


In this example, is line 16 referred to as instantiating an object pointer of a class, instantiating a pointer of type class, or something else?

When should objects be created like this?

What advantages and disadvantages are there to dynamically creating objects this way?
Jul 21, 2015 at 1:07pm
Bump.
Jul 21, 2015 at 1:42pm
In line 16, you're creating an instance of the class on the heap, by dynamic allocation.

You do this when:

1) You want to control the lifetime of the object, rather than having it destroyed when it falls out of scope

2) You don't know how much memory you'll need at compile-time, only at run-time. Typically, this is when allocating an array whose size you don't know at compile-time, although these days, you're better off using STL collection classes that manage their own memory dynamically.
Jul 21, 2015 at 3:55pm
Thank you. Would you still refer to the pointer as an object of the class?

Should you try to minimise the use of class pointers and instead stick to solid objects whenever possible?
Jul 21, 2015 at 4:14pm
The pointer is usually referred to as having the type "pointer-to-className". Which is why it is C++ style to write MyClass* a because a is of the type pointer-to-MyClass, whereas it is C style to write MyClass *a because when you dereference a (via *a), you get an object of type MyClass. You really shouldn't use pointers in C++ if you don't need them. Dynamic allocation and heap objects in general are slower than stack allocation and stack objects, so only use them if you need something to outlive its scope. Also, passing by pointer is basically pointless since passing by reference.
Jul 21, 2015 at 4:39pm
Thank you. Would you still refer to the pointer as an object of the class?

Not if you're being precise - which is often important. It's a pointer to an object of the class.

Should you try to minimise the use of class pointers and instead stick to solid objects whenever possible?

You should instantiate objects directly on the stack, if that's what you need, and you should dynamically allocate when that's what you need. In general, if you can get away with creating things on the stack, then do.

There are more uses for pointers than just for dynamic allocation. As shadowmouse says, modern C++ provides alternatives that are almost always better than using raw C-style pointers. However, those are advanced topics - as a beginner, there's nothing at all wrong with learning how to use pointers first, before moving on to the better alternatives such as references and smart pointers.
Last edited on Jul 21, 2015 at 4:39pm
Pages: 1234