So I was recently trying to get a piece of C++ code to compile and I just could not figure out what was going on.
Here's a sample roughly of what the code looked like. It's not quite the same code I was debugging, but it does spit out similar compiler outputs.
namespace space
{
template<typename type> class ClassA
{
protected:
int bounds;
public:
virtual ~ClassA(void)
{
}
virtual int doIt(void) = 0;
virtual int doIt2(void) = 0;
};
template<typename type> class ClassB : public ClassA<type>
{
protected:
ClassA<type> *parent;
public:
virtual ~ClassB(void)
{
}
virtual int doIt(void)
{
return bounds;
}
int doIt2(void)
{
return parent->bounds;
}
};
}
For the longest time I could not figure out why doIt2 wasn't calling properly. The actual code I was debugging was a bit more complicated, but I should have been able to quickly identify the problem and fix it.
The compiler message: 'ClassA::bounds' : cannot access protected member declared in class 'ClassA'
The message would highlight the access line in doIt2 where I try to retrieve the bounds value from parent.
My first thought was that the problem might have to deal with C++ template types not being right since I'm not particularly well-versed with C++ templates.
After double checking, then triple and quadruple checking the templates I decided that they were correct and that there must be some other problem. Needless to say, I chased red herring after red herring trying to figure out what was wrong.
So what was the actual problem? I forgot to declare ClassB as a friend to ClassA. This is one of those details that gets lost between Java programming and C++ programming.
In Java, even though the field bounds is protected I can still access it from anywhere in the same package. The closest equivalent in C++ are namespaces, though these really aren't that close at all.
So me being in a semi sleep-deprived state assumed (there's that magical 7 letter word which causes trouble) that I must be able to have access to bounds because not only was I in the same namespace, I was in the same file.
After taking a little break, I finally realized my mistake, shook my head and decided to write a blog post about the ordeal. Morale of the story? Take a break when you're stuck on a problem you just can't figure out. And get some sleep.
The fixed solution:
namespace space
{
template<typename type> class ClassB;
template<typename type> class ClassA
{
protected:
int bounds;
public:
virtual ~ClassA(void)
{
}
virtual int doIt(void) = 0;
virtual int doIt2(void) = 0;
friend class ClassB<type>;
};
template<typename type> class ClassB : public ClassA<type>
{
protected:
ClassA<type> *parent;
public:
virtual ~ClassB(void)
{
}
virtual int doIt(void)
{
return bounds;
}
int doIt2(void)
{
return parent->bounds;
}
};
}