In short words, I was trying to understand how forward referencing works inside a document, and I was trying to make this code compile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include <stdio.h>
int main() {
DummyClass * myReference = new DummyClass();
delete(myReference);
}
class FakeClass {
DummyClass myField;
};
class DummyClass{
FakeClass anotherField;
};
I had no luck! I would be very grateful if someone could lend a hand. I know this is a very basic question, but it's been ages since I had to work with C++
The compiler needs the full definition of the class before it can create an instance. That's because it needs to know how much space to allocate, which constructor to call etc.
The case you've posted, which each class contains an instance of the other, is impossible in C++. If FakeClass contains a DummyClass and DummyClass contains a FakeClass, then how big each each class? FakeClass has to be big enough to hold all its members, plus an instance of DummyClass. But DummyClass has to be big enough to hold all its instances plus an instance of FakeClass. It's like asking for two boxes, both big enough to hold the other.
If you really need this then the way around it is to have each class contain a pointer or reference to the other.
@dhayden, Many thanks for your clear explanation! That makes perfect sense. I'm very used to reference based languages such as C# and Java, and that's why I was not seeing the issue.
I was tring to get my head around it using pointers, and I came up with this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include <stdio.h>
class DummyClass;
class FakeClass;
class DummyClass{
FakeClass * sampleItem;
};
class FakeClass{
DummyClass * anotherItem;
};
int main() {
FakeClass myItem;
}
Is this the expected way to do it?
Also, I would appreciate it a lot if any C++ coder could lent me a hand. How whould you achieve the situation of 2 classes that need to be able to call methods of each other?
I'm trying to get this right:
- ParentNode::GetChildValue() should return int, not void
- const qualify methods wherever appropriate
- avoid leading underscore for variable names as:
"Don't overlegislate naming, but do use a consistent naming convention: There are only two must-dos: a) never use "underhanded names," ones that begin with an underscore or that contain a double underscore; ..." (p2 , C++ Coding Standards, Herb Sutter and Andrei Alexandrescu)
-
How whould you achieve the situation of 2 classes that need to be able to call methods of each other
@gunnerfunner Thanks for your clear and easy to follow explanation! Now I think I get it completely.
Also, I've learned the const modifier on method declarations, which is very nice.
I wish I'll be helping others too soon, when I learn a bit more.
Rather than having Parent::GetChildValue() and Child::GetParentName(), I think it would much more flexible to have Parent *Child::getParent() and Child *Parent::getChild(). That way you can do whatever you want with the parent and child.
Think about it. If you add 4 more attributes to the Parent class then will you add 4 more methods to the Child class to get the attributes of the parent? That makes little sense.
@dhayden: Thanks for your suggestion!
It was just a quick nasty sample code to ilustrate the referencing problem I was having. I've been woring in OOP for more than 15 years now, so I agree with both of you too! the Parent::GetChildValue() really really sucks, it was just put there to help me understand how the compiler works. Maybe worst example ever! XD
@gunnerfunner
You were quoting Sutter and Alexandrescu's book:
never use "underhanded names," ones that begin with an underscore or that contain a double underscore
Do they give a reason why?
AFAIK it is undefined behavior to
- Use names that begin with an underscore followed by a capital letter
- Use names that begin with two leading underscores
But both of those restrictions are weaker than what they suggest.
hat-tip to my mate kemort for nudging me on this few days back. some compilers do allow you to get away with the single underscore prefix but another compiler may not work.
There is absolutely nothing wrong with the use of identifiers like _myParent or _myChild in the above code.
These identifiers begin with an underscore; but they are not in the global namespace, they do not contain a double underscore, and the underscore at the beginning is not followed by an upper case letter.
For an actual use of valid identifiers beginning with an underscore in peer reviewed code,
see place holders _1 etc in boost:bind or boost::lambda.
Some identifiers are reserved for use by C ++ implementations and shall not be used otherwise; no diagnostic is required.
— Each identifier that contains a double underscore __
or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
— Each identifier that begins with an underscore
is reserved to the implementation for use as a name in the global namespace.
For the same reason using namespace std is discouraged, using single underscore prefix should also be - beyond immediate dangers and with minimal effort avoid storing problems down the line
> For the same reason using namespace std is discouraged, using single underscore prefix should also be
No, they are not the same or even similar.
Using namespace std is not merely discouraged; except where explicitly permitted, it is forbidden.
The behaviour of a C ++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. - IS
If this is about using namespace std;, this is what Sutter and Alexandrescu have to say (Item 59):
In short: You can and should use namespace using declarations and directives liberally in your implementation files after #include directives and feel good about it. Despite repeated assertions to the contrary, namespace using de clarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.
It appears to me that after saying "Don't overlegislate naming, but do use a consistent naming convention",
they have gone ahead and precisely that - overlegislate naming.
JLBorges - you've probably forgotten more C++ than I'll ever learn so I approach with great trepidation but the overwhelming evidence I'm seeing suggests not using the single prefix underscore which is the issue here. Perhaps namespace std was not the best analogy
'Favour not having user-defined names that begin with an underscore'
'C++ source code is much easier to read when names in the std namespace are qualified with std::'
are reasonable and good "guidelines" (or recommendations or best practices); I do consistently adhere to these two.
However, 'Never use names that begin with an underscore' is not a valid C++ programming "rule" -
(a must-do as suggested by Sutter and Alexandrescu).