How to overload constructor to instantiate polymorphic object?

Is this even possible in C++?
I want to create a classA object that contains a classB object.
If a classB object is passed in to the classA constructor, it becomes part of classA.
If a classB object is NOT passed to the constructor, classA constructor instantiates a default classB object.
Here is the tricky bit: classB is polymorphic, with subtypes classB1 and classB2.

This example does not compile:
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
class classB                //abstract base class
{
};

class classB1 : public classB
{
};

class classB2 : public classB
{
};

class classA
{
    private:
        classB& refObjB;    //note: should be initialized
    public:
        classA()            //error: uninitialized reference member
        {
            classB1 refObjB;
        }
        classA(classB& refObjB) : refObjB(refObjB) {}
};

int main()
{
    classB2 objB2;

    classA objA1;            //default classB1 object (this gets compile error)
    classA objA2(objB2);     //pass in classB2 object (this works)
}

Compile error:
1
2
3
4
5
6
7
8
$  g++ constructor_overload_default.cpp
constructor_overload_default.cpp: In constructor ‘classA::classA()’:
constructor_overload_default.cpp:18:9: error: uninitialized reference member in ‘class classBInterface&’ [-fpermissive]
         classA()
         ^~~~~~
constructor_overload_default.cpp:16:26: note: ‘classBInterface& classA::refObjB’ should be initialized
         classBInterface& refObjB;
                          ^~~~~~~

Apparently line 20 is not the way to initialize refObjB. Is there a way to make it work?
Last edited on
Thanks TheSmallGuy. That works! You are the smart guy.
What is the "static" in line 13 for?

This example works:
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
#include <iostream>

class classB                //abstract base class
{
    public:
        virtual void print()=0;
};

class classB1 : public classB
{
    public:
        virtual void print()
        {
            std::cout << "classB1" << std::endl;
        }
};

class classB2 : public classB
{
    public:
        virtual void print()
        {
            std::cout << "classB2" << std::endl;
        }
};

//both static and nonstatic lines compile:
//static classB1 ObjB1;
classB1 ObjB1;

class classA
{
    private:
        classB& refObjB;
    public:
        classA() : refObjB(ObjB1) {}
        classA(classB& refObjB) : refObjB(refObjB) {}
        void print()
        {
            refObjB.print();
        }
};

int main()
{
    classB2 objB2;

    classA objA1;            //default classB1 object
    classA objA2(objB2);     //pass in classB2 object

    objA1.print();
    objA2.print();
}


output:
1
2
classB1
classB2
In the preceding example, ObjB1 is instantiated in global space, so it will consume RAM if it's used or not.
In the real program, ObjB1 will be large.
This is a concern because the code will be compiled for an Arduino micro controller with little RAM.
Is there a way to instantiate the default ObjB1 in the classA() constructor?

Thanks.
Sorry I didn't mention that that classA is for a library.

Most users of the library will only use the default ObjB1.
The purpose of the default classA() constructor is so that users don't have to know about ObjB1.
Only users that need advanced functionality will instantiate a classB object and pass it to the classA(classB& refObjB) constructor.
So that's why I was looking for a way to instantiate a classB1 object in the default classA() constructor.
Last edited on
So why do you use reference at all?

Reference is restricted and cannot be left empty. Thus a [smart] pointer would be more appropriate which can be set to nullptr if not associated.
Hi coder777.
"So why do you use reference at all?"

refObjB needs to point to a classB object.
The application can not work without a classB object.
refObjB needs to point to a classB object.
The application can not work without a classB object.
I did not suggest to omit refObjB. Instead I suggested to change the type to a pointer since references are too restrictive in your case.
@coder777 now I see what you mean by "change the type to a pointer".
This works:
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
#include <iostream>

class classB                //abstract base class
{
    public:
        virtual void print()=0;
};

class classB1 : public classB
{
    public:
        virtual void print()
        {
            std::cout << "classB1" << std::endl;
        }
};

class classB2 : public classB
{
    public:
        virtual void print()
        {
            std::cout << "classB2" << std::endl;
        }
};

class classA
{
    private:
        classB* ptrObjB;
    public:
        classA()
        {
            classB1* ptrObjB1 = NULL;
            ptrObjB = new classB1;
        }
        classA(classB* ptrObjB) : ptrObjB(ptrObjB) {}
        void print()
        {
            ptrObjB->print();
        }
};

int main()
{
    classB2 objB2;

    classA objA1;           //default classB1 object
    classA objA2(&objB2);   //pass in classB2 object

                            //output:
    objA1.print();          //classB1
    objA2.print();          //classB2
}

output:
1
2
classB1
classB2

Thank you for your help.
The problem is that line 35 will leak memory. Each new should have a corresponding delete. Hence it should look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class classA
{
    private:
        classB* ptrObjB;
    public:
        classA() : ptrObjB(nullptr) // C++11: nullptr instead of NULL
        {
            classB1* ptrObjB1 = NULL;
            ptrObjB = new classB1;
        }
        classA(classB* ptrObjB) : ptrObjB(ptrObjB) {}
        void print()
        {
            if(ptrObjB) // Check if exists
              ptrObjB->print();
            else
              std::cout << "null" << std::endl;
        }
};


Consider using smart pointer, i.e. std::shared_ptr or std::unique_ptr

http://www.cplusplus.com/reference/memory/shared_ptr/?kw=shared_ptr
http://www.cplusplus.com/reference/memory/unique_ptr/?kw=unique_ptr

in order to prevent several problems with pointer like shallow copy, double free, or memory leak.
Topic archived. No new replies allowed.