By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,261 Members | 1,325 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,261 IT Pros & Developers. It's quick & easy.

Initialization list and inheritance

P: n/a
NT
Hi there!

I am puzzled by what I think must be a subtlety of C++ when
list-initializing member variables in derived classes...

Here's what I mean...

class A { // warning l337proggy alert! ;-)
public:
A(int v=9812); // default value provided since this base constructor
// is called by derived classes' constructors
~A();
int getValue();
public:
int value; // it's public, but I don't care!
};
A::A(int v) : value(v) {
cout<<"A() , "<<value<<endl;
}
A::~A() {
cout<<"~A()"<<endl;
}
int A::getValue() {
return value;
}
class B : public A {
public:
B(int v=1);
~B();
};
B::B(int v) {
cout<<"B() , "<<value<<endl; // value is still 9812
}
B::~B() {
cout<<"~B()"<<endl;
}
class C : public B {
public:
C(int v);
~C();
int setValue(int v);
};
C::C(int v) {
cout<<"C() , "<<value<<endl; // 9812 because of A::A()
value=v;
cout<<" "<<value<<endl;
}
C::~C() {
cout<<"~C()"<<endl;
}
int C::setValue(int v) {
value=v;
}
int main(void) {
B *b = new B(5);
C *c = new C(10);
cout<<b->getValue()<<endl;
cout<<c->getValue()<<endl;
c->setValue(32);
cout<<c->getValue()<<endl;
delete b;
delete c;
return 0;
}

Well, so far, so good... But, something weird's happening when I change
C::C() and use an initialization list instead of an assignment in the
body...

C::C(int v) : value(v) {
cout<<"C() , "<<value<<endl;
}

GCC (version 3.3) is really not happy with that!:

proggy.cpp:41: error: class `C' does not have any field named `value'

Ok, _now_ I'm confused! I thought derived classes had access to all
non-private data of their base class?

I guess there is something absolutely trivial that I'm missing here...
Yeah, hard to believe I'm been using C++ for years, isn'it? (albeit on a
_very_ on and -mostly- off basis...)

Is there someone to help?

NT
----
Linux/OS X
GCC 3.2
Dec 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
"NT" <ne*******@spymac.com> schrieb im Newsbeitrag
news:do**********@news.polytechnique.fr...
Hi there!

I am puzzled by what I think must be a subtlety of C++ when
list-initializing member variables in derived classes...

Here's what I mean...

class A { // warning l337proggy alert! ;-)
public:
A(int v=9812); // default value provided since this base constructor
// is called by derived classes' constructors
~A();
int getValue();
public:
int value; // it's public, but I don't care!
};
A::A(int v) : value(v) {
cout<<"A() , "<<value<<endl;
}
Ok, value is set to the value specified when A is constructed or 9812 as a
default value.
A::~A() {
cout<<"~A()"<<endl;
}
int A::getValue() {
return value;
}
class B : public A {
public:
B(int v=1);
~B();
};
B::B(int v) {
cout<<"B() , "<<value<<endl; // value is still 9812
}
You don't pass the value used to initialize B down to A, so value will
always get the default value. Use

B::B(int v): A(v) ...

do pass v to A.
B::~B() {
cout<<"~B()"<<endl;
}
class C : public B {
public:
C(int v);
~C();
int setValue(int v);
};
C::C(int v) {
cout<<"C() , "<<value<<endl; // 9812 because of A::A()
value=v;
cout<<" "<<value<<endl;
}
This constructor initializes A::value twice - once with A's default value
and then it is set to the value passed to C::C(int).
C::~C() {
cout<<"~C()"<<endl;
}
int C::setValue(int v) {
value=v;
}
int main(void) {
B *b = new B(5);
C *c = new C(10);
cout<<b->getValue()<<endl;
cout<<c->getValue()<<endl;
c->setValue(32);
cout<<c->getValue()<<endl;
delete b;
delete c;
return 0;
}

Well, so far, so good... But, something weird's happening when I change
C::C() and use an initialization list instead of an assignment in the
body...

C::C(int v) : value(v) {
cout<<"C() , "<<value<<endl;
}

GCC (version 3.3) is really not happy with that!:

proggy.cpp:41: error: class `C' does not have any field named `value'


And right it is. C does not have a member named 'value'. A has, but not C.
In an initialization list, you can only initialize members of a class, and
you can initialize direct base classes. So it should be

C::C(int v): B(v) ...

and of cause, B should take care that A is initialized properly, too.

HTH
Heinz
Dec 22 '05 #2

P: n/a
> B::B(int v) {
cout<<"B() , "<<value<<endl; // value is still 9812
}
because it initalises A with its default constructor having failed to
specify otherwise. The fact that A also has a constructor that takes an
int doesn't mean it will be automatically used. C::C(int v) : value(v) {
cout<<"C() , "<<value<<endl;
}

GCC (version 3.3) is really not happy with that!:


and so it shouldn't be as you can only initialise your own members and
your own immediate base class. There is one exception to the latter
part of that rule: if a class uses virtual inheritance then its derived
classes are still responsible for initialising it, eg

class A
{
public:
A( int );
};

class B : public virtual A
{
public:
B( int x ) : A( x )
{
};
};

class C : public B
{
C( int y ) : B ( y )
{
}
};

will fail because here C has to also initialise A. In fact one trick
that can be used to make B final is to use virtual inheritance for a
class that has only a private constructor, and declares your class as a
friend. You can use a template to achieve this.

template < typename T >
class Final
{
Final();
friend class T;
};

class MyClass : public virtual Final< MyClass >
{
// rest of class
};

(It would probably work just as well with private virtual inheritance).

Dec 22 '05 #3

P: n/a
Hi all!
this is the code:
#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void MyFunction(char *B[])
{
cout<<sizeof(B)<<endl; //(1)
}

int main()
{
char* B[]={"1","2","we"};
MyFunction(B);
cout<<sizeof(B)<<endl;//(2)

system("PAUSE");
return 0;
}

and this is the problem :
in the (1) cout I get the answer :4
and in the (2) cout I get 12!
How can I handle this please?


Dec 24 '05 #4

P: n/a
"Aris" <na******@hotmail.com> writes:
Hi all!
this is the code:
#include <iostream.h>
No such header, change to:
#include <iostream>
using std::cout;
using std::endl;
#include <stdlib.h>
Only needed for the call to system(), which shouldn't be there
anyway.
#include <stdio.h>
Remove, not using any functions from <stdio.h>
#include <string.h>
Remove, not using any function from <string.h>
void MyFunction(char *B[])
Same as:
void MyFunction(char** B)
(don't use all uppercase names, as they can easily be mistaken
for macros).
{
cout<<sizeof(B)<<endl; //(1)
Please indent your code. Parentheses aren't necessary, change to:
cout << sizeof B << endl;

sizeof B == sizeof(char**), which seems to be 4 on your system.
}

Please, please, please indent. (I do it for you this time).
And your code will be much easier to read if you use the
space bar wisely.
int main()
{
char* B[]={"1","2","we"};
should be const char* B[].
MyFunction(B);
cout << sizeof(B) << endl; // (2)
Parentheses not needed, remove:
cout << sizeof B << endl; // (2)
Here the type of B is an array of three char pointers, so
sizeof B == 3 * sizeof(char*). (In your case 3 * 4 = 12).
system("PAUSE");
Don't call system, unless you really must. The argument to system()
is system specific, which means it's more difficult to help you for
people not running the same operating system as you do.

My guess is that the purpose of the system("PAUSE") is to prevent
the program window from disappering when the progam is finished, but
there are better ways to do that. If you are using MSVC I think you
can start the program with some combination of shift, control, and
alt, with the function key that runs the program. (Try it or read the
documentation). Or you could open a command line window, and start
the program from there. If you really insist on pausing the program
you can call getchar (from <stdio.h>) or getline (from <iostream>)
to get similar behavior (waiting for enter instead of any keypress).
return 0;
}

and this is the problem :
in the (1) cout I get the answer :4
and in the (2) cout I get 12! How can I handle this please?


The reason for this behavior is that array type function arguments are
implicitly converted to a pointer to the first element of the array.

So when you declare a function as:

void func(char* array[]);

it means exactly the same thing as:

void func(char** array);

If the called function needs to know the size of the array, it must be
passed separatly to the function, since that information is lost when
the array is converted to a pointer to the first element.

The obvious workaround is to not use arrays at all, but the standard
library containers (vector, deque, or list).

Using vector your program becomes:

#include <vector>
#include <iostream>
#include <string>

using std::vector;
using std::cout;

char* init[] = { "1", "2", "we" };

void MyFunction(const vector<string>& b)
{
cout << "The vector b has " << b.size() << " elements\n";
}

int main()
{
vector<string> a(init, init + sizeof initial_values / sizeof *init);
MyFunction(a);
cout << "The vector a has " << a.size() >> " elements\n";
return 0;
}

/Niklas Norrthon
Dec 28 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.