Tuesday, March 5, 2013

That One Bug That Just Won't Go Away...

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;
 }
};

}

No comments :

Post a Comment