473,324 Members | 2,370 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

Initialization list and inheritance

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
4 3941
"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
> 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
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
"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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Jacek Dziedzic | last post by:
Hi! A) Why isn't it possible to set a member of the BASE class in an initialization list of a DERIVED class constructor (except for 'calling' the base constructor from there, of course)? I even...
8
by: Marcin Kalicinski | last post by:
Hi, Constructor of derived class needs to do some complex things before it calls base class constructor. There is an ugly solution: bool ComplexThingToDo() { // ... return false; //...
4
by: Anton Pervukhin | last post by:
Hi everybody! I have a small problem regarding the initialization of pointer to the file stream under some conditions. Imagine a class which has a pointer to output file stream and some...
10
by: emma middlebrook | last post by:
Hi I discovered that if you declare a structure (and not 'new()' it) you can then separately initialize its members and the compiler counts those separate statements as a full initialization....
6
by: anongroupaccount | last post by:
class CustomType { public: CustomType(){_i = 0;} CustomType(int i) : _i(i) {} private: int _i; }; class MyClass
5
by: toton | last post by:
Hi, I can initialize an array of class with a specific class as, class Test{ public: Test(int){} }; Test x = {Test(3),Test(6)}; using array initialization list. (Note Test do NOT have a...
1
by: Sandro Bosio | last post by:
Hello everybody, my first message on this forum. I tried to solve my issue by reading other similar posts, but I didn't succeed. And forgive me if this mail is so long. I'm trying to achieve the...
4
by: Jess | last post by:
Hello, I tried several books to find out the details of object initialization. Unfortunately, I'm still confused by two specific concepts, namely default-initialization and...
20
by: JohnQ | last post by:
The way I understand the startup of a C++ program is: A.) The stuff that happens before the entry point. B.) The stuff that happens between the entry point and the calling of main(). C.)...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.