views:

635

answers:

6

Imagine I have a C++ class Foo and a class Bar which has to be created with a constructor in which a Foo pointer is passed, and this pointer is meant to remain immutable in the Bar instance lifecycle. What is the correct way of doing it?

In fact, I thought I could write like the code below but it does not compile..

class Foo;

class Bar {
public:
    Foo * const foo;
    Bar(Foo* foo) {
        this->foo = foo;
    }
};

class Foo {
public:
  int a;
};

Any suggestion is welcome.

+7  A: 

You need to do it in an initializer list:

Bar(Foo* _foo) : foo(_foo) {
}

(Note that I renamed the incoming variable to avoid confusion.)

Jim Buck
+1, although I've recently learned here that variables starting with underscore now *officially* reserved ;-)
Michael Krelin - hacker
Only if they are followed by an uppercase letter.
GMan
or are in namespace scope! Or are followed by another underscore. So yeah, it's technically legal in this case, but I'd say it's easier to just pretend they're reserved, and not use them at all. :)
jalf
jalf, but I like them. I'd rather break the law.
Michael Krelin - hacker
@hacker: I used to think so, too. Got bitten. Nowadays I find a trailing underscore just as fine.
sbi
About the rename, it is one of the few places where you can write the same name twice in an expression with different meaning: 'Bar(Foo* foo) : foo(foo) {}' will work appropriatedly as in an initialization list the first foo must be a base class or an attribute of the current class, but inside the parenthesis the parameter hides the attribute and thus 'foo' is the incoming parameter there.
David Rodríguez - dribeas
@dribeas: While the compiler might accept something like this, I wouldn't. Not everything should be done that could be done.
sbi
A: 

Use a reference:

Foo& foo;
Bar(Foo& f) : foo(f) { }

You can then refer to foo easily in Bar:

foo.doSomething();
AraK
I vote as "negative" because if it was the only answer, I could have wrongly thought that using a reference was the only way to achieve it, while instead as the other answer shows, the trick is the initializer list.
puccio
IMHO, references are much more elegant in this case because the pointer mustn't get changed at all after it gets initialized :)
AraK
But the question was how to initialize pointer.
Michael Krelin - hacker
@hacker I just said what I believe is a better way to do the same thing.
AraK
A: 

try: Bar(Foo* xfoo) : foo(xfoo) {}

John Ledbetter
+1  A: 

Initializing const members and other special cases (such a parent classes) can be accomplished in the initializer list

class Foo {
private:
   const int data;
public:
   Foo(int x) : data(x) {}
};

Or, similarly, for parent initialization

class Foo {
private:
   int data;
public:
   Foo(int x) : data(x) {}
};

class Bar : Foo {
public:
   Bar(int x) : Foo(x) {}
};
ezpz
+1  A: 

You need to initialize foo in the initializer list.

class Bar {
public:
Foo* const foo;
Bar(Foo* f) : foo(f) {}

};

KeithB
+3  A: 

I believe you must do it in an initializer. For example:

Bar(Foo* foo) : foo(foo) {
}

As a side note, if you will never change what foo points at, pass it in as a reference:

Foo& foo;

Bar(Foo& foo) : foo(foo) {
}
SingleShot
+1: Use references wherever you want, pointers where you need.
David Rodríguez - dribeas