views:

116

answers:

1

I have a problem with Visual C++ 2005, where apparently inner classes with the same name but in different outer classes are confused.

The problem occurs for two layers, where each layer has a listener interface as an inner class. B is a listener of A, and has its own listener in a third layer above it (not shown).

The structure of the code looks like this:

A.h

class A
{
public:
    class Listener
    {
    public:
        Listener();
        virtual ~Listener() = 0;
    };
    // ...
};

B.h

class B : public A::Listener
{
    class Listener
    {
    public:
        Listener();
        virtual ~Listener() = 0;
    };
    // ...
};

A::Listener() and A::~Listener() are defined in A.cpp.

B.cpp

B::Listener::Listener() {}
B::Listener::~Listener() {}

I get the error

B.cpp(49) : error C2509: '{ctor}' : member function not declared in 'B'

The C++ compiler for Renesas sh2a has no problem with this, but then it is more liberal than Visual C++ in some other respects, too.

If I rename the listener interfaces to have different names the problem goes away, but I'd like to avoid that (the real class names instead of A or B are rather long).

Is what I'm doing correct C++, or is the complaint by Visual C++ justified?

Is there a way to work around this problem without renaming the listener interfaces?

+1  A: 

Hello starblue,

the code you posted produced the same compiler error you described on my machine. I'm not so sure myself what the problem exactly is, but I have a feeling that inherting from a pure virtual class and declaring a pure virtual class within the descendant might not be a good idea.

I managed to compile a modified version, maybe this helps you solve your problems:

class OuterA
{
  public:
    class Listener
    {
      public:
        Listener() {}
        virtual ~Listener() = 0 {}
    };

    OuterA() {}
    ~OuterA(){}
};

class OuterB : public OuterA::Listener
{
  public:
    class Listener
    {
      public:
        Listener()  {}
        ~Listener() {}
    };

    OuterB()  {}
    ~OuterB() {}
};

// EDIT to avoid inline ctor and dtor

If you use typedefs to hide the names of the Listeners at least my demo code compiles and links:

// header

class OuterA
{
  public:
    class Listener
    {
      public:
        Listener();
        virtual ~Listener() = 0;
    };

    OuterA();
    ~OuterA();
};   

class OuterB : public OuterA::Listener
{
  public:
    class Listener
    {
      public:
        Listener();
        virtual ~Listener() = 0;
    };

    OuterB();
    ~OuterB();
};

// implementation

OuterA::OuterA(){}
OuterA::~OuterA(){}

OuterA::Listener::Listener(){}
OuterA::Listener::~Listener(){}

typedef OuterB::Listener BListener;

OuterB::OuterB() {}
OuterB::~OuterB(){}

BListener::Listener(){}
BListener::~Listener(){}
Holger Kretzschmar
Unfortunately without declaring the constructors and destructors inline this leads to duplicate symbols when linking. Declaring them inline is not possible, because it violates our coding rules (checked by QAC).
starblue
since i like riddles like this i tried another trick - using a typedef to hide the name works
Holger Kretzschmar
Nice, I'll try that next week.
starblue
That works, also with the sh2a target compiler. It has the minor issue that Eclipse sees a syntax error for the constructor.
starblue