Setup:
class A {
public:
void a() {}
};
class B {
public:
void b() {}
};
class C: public A, public B {
public:
void c() {}
};
What (I thought) I should be able to do:
C* foo = new C();
foo->b();
And I get the following linker error from GCC:
`... undefined reference to 'C::b(void)'`
If I use explicit scope resolution it works, as in:
C* foo = new C();
foo->B::b();
A, B, and C share no members with similar signatures, so I know nothing is being hidden. Two questions:
1) Why, theoretically, am I not able to access public base class members implicitly?
2) What (if anything) in practice can I do to avoid this annoying syntax?
I can continue development with the explicit syntax (although I'd rather be rid of it) but I'm more looking to learn something here about my (apparently incorrect) knowledge of public inheritance in C++.
Cheers!
EDIT: Sorry, updated the sample code - some bad mistypes in my original.
EDIT2: Here's the (relevant parts of) the real code: from src/creature.h:
#include "container.h"
#include "identifiers.h"
class Creature: public Identifiers, public Container {
public:
Creature( void );
Creature( const Creature& ref );
virtual ~Creature( void );
};
from src/identifier.h:
class Identifiers {
public:
Identifiers( void );
Identifiers( const Identifiers& ref );
~Identifiers( void );
};
from src/container.h:
class Container {
public:
Container( std::string (Object::*getName)( void ) const );
Container( const Container& ref );
~Container( void );
void add( Object* object );
void add( const std::list<Object*>& objects );
void remove( Object* object );
void remove( const std::list<Object*>& objects );
};
from src/container.cpp:
Container::Container( std::string (Object::*getName)( void ) const ) {
_getName = getName;
return;
}
Container::Container( const Container& ref ) {
_getName = ref._getName;
return;
}
Container::~Container( void ) {
while ( !objectList().empty() ) {
delete objectList().front();
objectList().pop_front();
}
return;
}
void Container::add( Object* object ) {
objectList().push_back( object );
return;
}
void Container::add( const std::list<Object*>& objects ) {
objectList().insert( objectList().end(), objects.begin(), objects.end() );
return;
}
void Container::remove( Object* object ) {
objectList().remove( object );
return;
}
void Container::remove( const std::list<Object*>& objects ) {
for ( std::list<Object*>::const_iterator it = objects.begin(); it != objects.end(); ++it ) {
remove( *it );
}
return;
}
from the application itself:
bool CmdWear::execute( Creature* creature, const std::string& args ) {
std::list<Object*> objects;
Object* removed = NULL;
std::string error;
objects = creature->searchObjects( args );
for ( std::list<Object*>::iterator it = objects.begin(); it != objects.end(); ++it ) {
if ( creature->wear( *it, error, removed ) ) {
creature->remove( *it );
}
}
return true;
}
Notes:
1) All methods shown here are defined in their appropriate .cpp file.
2) Each associated object file compiles just fine. Only the linker fails at the last step of linking all the object files together.
3) GCC spits out: undefined reference to `Creature::remove(Object*)' unless I qualify explicitly the scope by saying:
creature->Container::remove( *it );
Makefile:
PROJECT = symphony
CPPC = g++
FLAGS_DEV = -ggdb3 -ansi -Wall -Werror -pedantic-errors
LIBS = `pcre-config --libs` `mysql_config --libs`
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = .
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst src/%.cpp,obj/%.o,$(SRC_FILES))
dev: $(OBJ_FILES)
$(CPPC) $(LIBS) $(FLAGS_DEV) $(OBJ_FILES) -o $(BIN_DIR)/$(PROJECT)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CPPC) -c $(FLAGS_DEV) $< -o $@