|
-
September 15th, 2010, 10:18 AM
#1
Help - how to initialize reference variable?
Hi,
This is an urgent issue so your help would be highly appreciated.
The following code is extracted from a real project.
Code:
#include <iostream>
using namespace std;
class B
{
public:
B(const int &n) : i(n)
{
cout << "In B constructor" << endl;
}
private:
int &i;
};
int main()
{
int i = 28;
B b(i);
return 0;
}
In this code snap, B::i must be a reference and B's constructor must take "const int &n". When building this code, I got compile error:
const_constructor.cpp: In constructor 'B::B(const int&)':
const_constructor.cpp:8: error: invalid initialization of reference of type 'int&' from expression of type 'const int'
Could someone please tell me how I fix this compile error?
Thanks,
BJT
Last edited by BJT; September 15th, 2010 at 10:21 AM.
-
September 15th, 2010, 10:28 AM
#2
Re: Help - how to initialize reference variable?
You either need to drop the const qualifier on the constructor argument, or else add one to the member i. You can't go from a const reference to a non-const reference without a cast (and you shouldn't use a cast unless you're positive one is necessary).
You should be aware either way that the class B will not be able to auto-generate a copy constructor since it has a reference member. You should therefore either write one yourself, or else make B explicitly uncopyable by declaring the cctor and operator= as private. Alternatively, if you store i as an (unowned) pointer rather than a reference, then the copying problem goes away.
-
September 15th, 2010, 10:37 AM
#3
Re: Help - how to initialize reference variable?
 Originally Posted by Lindley
You should be aware either way that the class B will not be able to auto-generate a copy constructor since it has a reference member.
I think that the copy constructor can be implicitly defined even with a reference member. It is the copy assignment operator that has a problem here, but we normally either implement or disable the both of them together.
-
September 15th, 2010, 10:40 AM
#4
Re: Help - how to initialize reference variable?
 Originally Posted by Lindley
You should be aware either way that the class B will not be able to auto-generate a copy constructor since it has a reference member. You should therefore either write one yourself, or else make B explicitly uncopyable by declaring the cctor and operator= as private. Alternatively, if you store i as an (unowned) pointer rather than a reference, then the copying problem goes away.
Really? In my experience, the compiler can still auto-generate a copy constructor, since references can be copy-constructed. It is only the assignment operator that the compiler cannot generate.
EDIT: laserlight beat me to it.
Last edited by HighCommander4; September 15th, 2010 at 04:40 PM.
Old Unix programmers never die, they just mv to /dev/null
-
September 15th, 2010, 10:49 AM
#5
Re: Help - how to initialize reference variable?
You're both correct, I misspoke. Same caveats apply though.
-
September 15th, 2010, 10:58 AM
#6
Re: Help - how to initialize reference variable?
After add "const" to B::i, then the code posted ABOVE can be compiled but it does not fix the actual problem in the real project.
(1) Class B in real project is a base class. Derived classes pass a const variable to the base class B. So it's better to keey the incoming parameter as const. Otherwise, all derived class need to be changed to pass a non-const parameter.
(2) Class B has a member function setN(const int &n). It's added to the following code. When compile the code, I got another error:
const_constructor.cpp: In member function 'void B::setN(const int&)':
const_constructor.cpp:22: error: assignment of read-only location
I think this is caused by adding "const" to B::i
Is it possible to keep const in B's constructor and let setN() to change B::i in run time?
Code:
#include <iostream>
using namespace std;
class B
{
public:
B(const int &n) : i(n)
{
cout << "In B constructor" << endl;
}
void setN(const int &n);
private:
const int &i;
};
void B::setN(const int &n)
{
i = n;
}
int main()
{
int i = 28;
B b(i);
b.setN(i);
return 0;
}
Last edited by BJT; September 15th, 2010 at 11:30 AM.
-
September 15th, 2010, 11:31 AM
#7
Re: Help - how to initialize reference variable?
Any suggestion would be appreciated.
Thanks,
BJT
-
September 15th, 2010, 11:53 AM
#8
Re: Help - how to initialize reference variable?
 Originally Posted by BJT
Derived classes pass a const variable to the base class B.
The key question in my mind is why they're doing this. Could you give an example?
If the goal of setN() is to update the value indicated by the reference, and that value corresponds to some member of a derived class, then why not make setN() virtual and let the derived classes override it?
-
September 15th, 2010, 12:34 PM
#9
Re: Help - how to initialize reference variable?
I used reference members only one or two times within 18 years C++. Actually I couldn't think a good reason why that is necessary, especially if a user of a derived class must provide the referenced variable. It doesn't seem to be a good design and probably offends encapsulation principle. How will you prevent those users from providing a local variable which goes out-of-scope like in the code below?
Code:
D* X::f()
{
int i = 100;
return new D(&i);
} // kaboom
I remember when I once used a reference member I provided the referenced variable myself:
Code:
class X
{
Y & y;
public:
X() : y(*(new Y(0))) {}
X(int i) : y(*(new Y(i))) {}
X(const X& x) : y(*(new Y(x.y))) {}
virtual ~X() { delete &y; }
};
There was a reason why I used a reference member and not a pointer member but I didn't know what was the case anymore. The difference to your code is that the reference was managed by the class itself and that there is no way to spoil the reference address from outside, not even from derived classes.
-
September 15th, 2010, 01:34 PM
#10
Re: Help - how to initialize reference variable?
 Originally Posted by Lindley
The key question in my mind is why they're doing this. Could you give an example?
If the goal of setN() is to update the value indicated by the reference, and that value corresponds to some member of a derived class, then why not make setN() virtual and let the derived classes override it?
This is a very good question that forces me to go back and check the original code in more details. The project class structure looks like Dn -> ... -> D2 -> D1 -> B (base class). Several properties are distributed (initialized) to different classes via their constructors based on the nature of these properties.
Not very sure about the reason why "const int &i", instead of "const int i", is used in class B but variable "&i" or "i" should indeed be in class B. "const int &i" used to be initialized in constructor, and then stay unchanged. Now for some reason we need to change the value of the variable pointed by &i after it's initialized. That's why setN() is introduced.
To keep using &i at least for now, the code snap is changed to the following one by using const_cast. Does it look okay, or does it have any potential issues?
Code:
#include <iostream>
using namespace std;
class B
{
public:
B(const int &n) : i(*const_cast<int*>(&n))
{
cout << "In B constructor" << endl;
}
void setN(const int &n);
private:
int &i;
};
void B::setN(const int &n)
{
i = n;
}
int main()
{
int i = 28;
B b(i);
b.setN(i);
return 0;
}
Thanks,
BJT
-
September 15th, 2010, 01:44 PM
#11
Re: Help - how to initialize reference variable?
 Originally Posted by itsmeandnobodyelse
... Actually I couldn't think a good reason why that is necessary, especially if a user of a derived class must provide the referenced variable. It doesn't seem to be a good design and probably offends encapsulation principle. How will you prevent those users from providing a local variable which goes out-of-scope like in the code below?
Yes, agree. I don't see a good reason why it's necessary either. Maybe it was designed that way originally for supporting something, and later that "something" was removed but the reference was not changed accordingly.
-
September 16th, 2010, 05:41 AM
#12
Re: Help - how to initialize reference variable?
 Originally Posted by BJT
This is a very good question that forces me to go back and check the original code in more details. The project class structure looks like Dn -> ... -> D2 -> D1 -> B (base class). Several properties are distributed (initialized) to different classes via their constructors based on the nature of these properties.
Not very sure about the reason why "const int &i", instead of "const int i", is used in class B but variable "&i" or "i" should indeed be in class B. "const int &i" used to be initialized in constructor, and then stay unchanged. Now for some reason we need to change the value of the variable pointed by &i after it's initialized. That's why setN() is introduced.
To keep using &i at least for now, the code snap is changed to the following one by using const_cast. Does it look okay, or does it have any potential issues?
Using a reference member - same as with a pointer member - has the advantage that the member can be in shared memory or be a global variable so that it may be initialized differently and to a time where no instance of the class B already exists. The same you normally can only do with static class members but which are singletons then. To find out whether you could change it to non-reference you would need to check each single input variable for the i member of baseclass B and find out where they take the integer from and how (and to what time) that integer was initialized. You also would need to find out if there was any const_cast (or C cast) on those variables after the class instance of B (or derived class) was constructed.
For the implementation I would let it a const int and do the cast in the SetN. So your change only is in the new function and doesn't reflect old code.
Code:
#include <iostream>
using namespace std;
class B
{
public:
B(const int &n) : i(n)
{
cout << "In B constructor" << endl;
}
void setN(int n);
private:
const int & i;
};
void B::setN(int n)
{
int * pi = const_cast<int*>(&i);
*pi = n;
}
int main()
{
const int i = 28;
B b(i);
b.setN(i);
return 0;
}
Last edited by itsmeandnobodyelse; September 16th, 2010 at 05:44 AM.
-
September 16th, 2010, 07:01 AM
#13
Re: Help - how to initialize reference variable?
I wouldn't bother with a reference member, it is just too restricting. You can get the exact same behavior with a member pointer, without all that hassle.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
September 16th, 2010, 10:10 AM
#14
Thanks everyone for your valuable information and help!
Thanks everyone for your valuable information and help!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|