How to initialize a base class constructor?

Hello,

I am working my way through Object Oriented programming in C++ from Robert Lafore and I am stuck with one exercise where he calls a base class constructor from a derived class.

I try to use a char array constructor in the baseclass to initialize the variable sstr. When calling it from a derivedclass like this:

 
derivedclass(char s[], j) : baselcass(s), i(j) {}


sstr gets initizialized but when calling it like this:

1
2
3
4
5
derivedclass(char s[], j)
   {
      baselcass(s);
     i = j;
   }


I receive errors with g++. Can anyone explain why and how to circumvent this issue? I would like to be able to call the baseclass constructor from the body of the derived constructor so I can make some adjustments to the char array.

For a complete code listing see below (and any other constructive remarks are very welcome)

Cheers,
Hans

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
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <cstring>
using namespace std;   //bad habit

class baseclass
    {
	protected:
	    static const int SZ = 40;
	    char sstr[SZ];
	public:
	    baseclass()
		{
		    sstr[0] = '\0';
		}
	    baseclass(char s[])
		{
		    strcpy(sstr, s);
		}
	    void showstr()
		{
		    cout << sstr << endl;
		}
    };

class derivedclass : public baseclass
    {
	private:
	    int i;
	public:
	    derivedclass() : baseclass(), i(0)
		{}
	    derivedclass(char s[], int j) : baseclass(s)  //this works but no way to change s
		{
		    i = j;
		}
	    void showderived()
		{
		    showstr();
		    cout << "\nI has the value of: " << i << endl;
		}
    };

class devcl : public baseclass
    {
        private:
            int i;
        public:
            devcl() : baseclass(), i(0)
                {}
            devcl(char s[], int j)
                {
                    i = j;
		    //baseclass(s);    //this results in a compiler error
		    char t[SZ];
		    baseclass(strcpy(t, s)); 	//is this the only way to get a char array in baseclass
						//without using pointers?
						//in baseclass object doesn't get initialized. Why?
                }
            void showderived()
                {
                    showstr();
                    cout << "\nI has the value of: " << i << endl;
                }
    };


int main()
    {
	cout << "Zero argument constructor";
	baseclass str1;
	str1.showstr();
	cout << "\nArgument constructor" << endl;
	baseclass str2 = "This is a string.";
	str2.showstr();

	cout << "\n-------------------------";
	cout << "\nZero argument constructor";
	derivedclass str3;
	str3.showderived();
	cout << "\nArgument constructor" << endl;
	derivedclass str4("A few words.", 9);
	str4.showderived();

	cout << "**************************";
	cout << "\nArgument constructor" << endl;
	devcl str5("A little line.", 12);
	str5.showderived();   //the sstr in the baseclass is not initialized

	return 0;
    }
The syntax to call the base constructor is using initialization lists ( the : baseclass ( ) thing )
Once you get in the body of the constructor your object has already been constructed so you can't call the base constructor.
If you use C++ strings instead of char arrays you'll have much less trouble and btw, array parameters are pointers
Bazzy,

thanks for the clarification. The idea of the exercise was to make your own string class with buffer protection (in a crude way). There was a base class called String and a derived class called Pstring (protected string). The derived class should check the length of the input and then cut of any remaining data. Then it creates an object of type String.

Below is the code.

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
class String
	{
		protected:
			static const int SZ = 30;
			char str[SZ];
		public:
			String()
				{ str[0] = '\0'; }
			String( char s[] )
				{ strcpy(str, s); }
			void display() const
				{ cout << str; }
			operator char*()
				{ return str; }
	};


class Pstring : public String
	{
		public:
			Pstring( char s[] );
	};

Pstring::Pstring( char s[] )
	{
		if (strlen(s) > SZ-1)
			{
				int j;
				for(j = 0; j < SZ-1; j++)
					str[j] = s[j];
				str[j]='\0';
		} else 
				String(s);
	}


I suppose this setup is flawed and the call to String(s) should just be a strcpy(str, s) statement, right?

Cheers,
Hans
To be honest, your base class has the responsibility to safely construct itself from its constructor parameters. It seem like a strange design decision to subordinate that task to a sub-class.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class devcl : public baseclass
    {
        private:
            int i;
        public:
            devcl() : baseclass(), i(0)
                {}
            devcl(char s[], int j)
                {
                    i = j;
		    //baseclass(s);   //*****I wouldn't have thought that this would cause a compiler error*****
		   
                    //These next two line together is just the same as the one above
                     char t[SZ];
		    baseclass(strcpy(t, s)); 					
						
                }
            void showderived()
                {
                    showstr();
                    cout << "\nI has the value of: " << i << endl;
                }
    };



The c++ statement format of a typename followed by some or no values in parenthesis
creates a temporary variable of that type (it is unamed because you have not given it an identifier);
For example:
std::string ("helo world");

So your baseclass(s) was creating a baseclass variable - not initializing the baseclass part of the derived class as you hoped.

As already pointed out - baseclass initialization is done in the initialization list ( in that list baseclass(s) means initialise the basclass not create a baseclass variable).

Last edited on
@Galik: you are absolutely right about the responsibility of the base class when it comes to safely constructing parameters. This was however just an exercise from the book and well, it served its purpose. It is somewhat clearer now what you can and can't do and what happens when. Thanks for pointing me to the definition of the strncpy, that third parameter is the clue!

@guestgalkan: thanks, I think I understand why things went wrong now....
Topic archived. No new replies allowed.