Pointer to a class gets an arguement or am I dumb?

Hi everyone,

As the title suggest I have a weird problem with the following class and its constructor (and yes it works):
1
2
3
4
5
6
7
class SolverBase {
public:
  Block *m_block;

  SolverBase(Block* block): m_block(block){};
  virtual ~SolverBase(){};
etc...


My problem is the bolded part. Since block and m_block are both supposed to be
pointers to different objects, what the heck does this statement suppose to mean????

thanks a bunch in advance and cheers,
nimra
Hmmm.. yeah this syntax is something that I think is a bit crazy. I'm not entirely sure how this is defined in the standard, but that syntax basically means "copy the value of the variable block to the variable m_block". For most data types you can use this syntax.

I should also add that copying a pointer to another pointer means they will both point to the same object.
Last edited on
You need new memory for m_block member

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SolverBase 
{
public:
  Block *m_block;

  SolverBase(Block* block) : 
          m_block(new Block(*block)) {  }

  virtual ~SolverBase()
  {
         delete m_block;
  }

// ...
};


Is this what you asked?
Or are you asking about initializer list?
Hi

thanks for the answer man!

so basically something like that is only allowed in defining the constructor right? I haven't seen anything like that used for ,say , int's in a main function (and I am sure it won't work)

Are there any specific reasons, as why one would do something like that?
Are you talking about initializer list?

I suppose yes, initializer list is only allowed in:
- constructors,
- copy constructors,
- move constructors

and also something similar is
- inheritance list

initializer list is followed by :. colon
initialization is done in order of member variables declaraiton, (not in order of initialization list.

pointers should allmost allways have heap memory so that 2 or more objects of same type do not point to the same chunk of memory.

inheritance list is done with somwhat differerent rules,
for example virtual base class objects are constructed first in order of inheritance and other "non virtual objects" are initilized in order of initialization list respecting the inheritance of base objects of objects being inherited, object it self is constructed last ... etc.. etc..


So yes main funciton may not have an initializer list as well as any other function, class method or template.

hope this helps a little :)
Last edited on
Just a little bit about why you might need that syntax.

Consider this example, which definitely might occur in the real world:

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
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <ctime>

using namespace std;

class Shape
{
public:
	Shape(int nVertices) { m_nVertices = nVertices; }

protected:
	int m_nVertices;
};

class Square : public Shape
{
public:
	Square(int nWidth) 
	{
		m_nWidth = nWidth;
		m_nVertices = 4;
	}

protected:
	int m_nWidth;
};

int main()
{ 
	Square b(5);
	return 0;
}


Try to compile it. It won't work because Shape has no constructors that take 0 parameters. But we aren't instantiating a shape anywhere! We are creating a square, and passing in a size to that constructor (which it requires). But even so, Square still has to construct itself as a Shape, so it (by default) calls its parent class's constructors with no parameters.

1
2
3
Square(int nWidth) 
	{     // <-------- Here, Square implicitly calls 'Shape::Shape()'
		m_nWidth = nWidth;


How to fix? We tell Square to use a different constructor, using an initializer list

1
2
3
4
Square(int nWidth)  : Shape(4)
	{
		m_nWidth = nWidth;
        }


And now it compiles and works as expected. The same thing would apply if we had another class "House", which maybe uses a square to define where it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class House
{
public:
	House()
	{
		
	}

	void SetBoundingSquare(const Square & bs)
	{
		m_BoundingSquare = bs;
	}

protected:
	Square m_BoundingSquare;

};


If you add this to the code, again, an error, that there is no default constructor for Square to construct m_BoundingSquare. This is because each data member of the class House has to be constructed, which occurs at about the same place parent constructor(s) are called. So the compiler is implicitly calling Square::Square() to construct m_BoundingSquare, which unfortunately doesn't exist! The solution is to add m_BoundingSquare into the initializer list with an appropriate value:

1
2
3
4
House() : m_BoundingSquare(5)
{
		
}



And all is right in the world again :)
Last edited on
In addition, it's generally a good idea to use the initializer list with simple objects since this means that the constructor of the object will be called with the parameters you give, and not the default constructor, saving you some assignment operations later on.
Oh that's a lot of answers, thanks guys ang gals,

@codekiddy: the block object from class Block was already allocated dynamically outside of the class, so that is not a problem.

@everybody else, the concept I was not familiar with was the so-called "Initialization list", I thought
after : only the constructor of the base class could be called, that was certainly not the case, as I understand it now.

one thing is still a mystery to me though: what difference would have it made, if I would have written;

 
m_block = block


in the constructor definition later on. Or are they the same thing.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Foo
{
Block *m_block;
public:
Foo(Block *block)
//Here the default constructor of Block* is called before Foo's constructor,
//so that the object exists before Foo tries to use it.
{
m_block = block; //Here the assignment operator of Block* is called, to copy
                           //the value of block into m_block.
}
};

class Bar
{
Block *m_block;
public:
Bar(Block *block):m_block(block){}
//In this case, instead of using the default constructor to construct m_block,
//its copy constructor is called, automatically setting it to the value of block.
//This means we don't have to do "m_block = block" later on, because
//m_block already holds the value of block.
};


Therefore, the initialization list can save you a function call. Also, I assume some people find it easier to read (me included). The only problem using this method is that you can't verify that "block" is a valid value before assigning it to "m_block".

EDIT: Forgot some semicolons.
Last edited on
The only problem using this method is that you can't verify that "block" is a valid value before assigning it to "m_block".
What do you mean? Sure you can... Although I don't know what you would do, it's either NULL(0) or not right?

You can use Ternary operators inside member initialization in the initialize list.

So doing this...
SolverBase(Block* block): m_block((block)?block:0){};


Is the same thing as doing this if block were NULL
SolverBase(Block* block): m_block(0){};

Or this if block wasn't NULL
SolverBase(Block* block): m_block(block){};
Thanks a lot to all

I understand the concept now!

Topic archived. No new replies allowed.