Why is this explicit scope resolution necessary?
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 $@
You can't call a function that's not defined. gcc's telling you exactly that. And foo::B->b();
is not valid C++. It doesn't compile with either g++
or cl.exe
.
If you wrote
public:
void b() {}
it would work.
I don't think that either of the snippets that you've posted should compile.
class C: public A, public B {
public
void c();
};
You need a :
after the public
access specifier.
C foo = new C();
foo->b();
You are trying to initialized a C
from a pointer to dynamically allocated C
object. .
not ->
is the correct operator to call a function on an object type. ->
is for pointer types (or objects with an overloaded ->
operator) only.
You need something like:
C foo;
foo.b();
I'm not sure how the snippet that you say works actually compiles.
C foo = new C();
foo->b();
This is wrong, you probably wanted:
C foo;
foo.b();
it should work, as long as that error you're getting is not a linker error (I'm not familiar with the gcc suite). If it's a linker error it means your function doesn't have a body, so there's nothing to call.
The error you get is a linker error, not a compiler error. That implies that your code compiles -- good. The linker is complaining because it can't find the definition of the function. Is the definition in a different C++ file? Perhaps there is a file B.cpp which contains:
#include "B.h"
void B::b() {
// do something nifty here
}
and then there is a separate file C.cpp which contains:
#include "C.h"
C *
func() {
C* foo = new C();
foo->b();
return foo;
}
If you only compile C.cpp, such as:
g++ -Wall -Wextra C.cpp
Then you will get the linker error you see.
Perhaps you want to do a partial compilation and then link all the .o files later?
g++ -Wall -Wextra -c C.cpp
Or perhaps you want to compile them all together and link at the same time?
g++ -Wall -Wextra A.cpp B.cpp C.cpp
Try this out :
C *foo = new C();
And where is the function definitions ??.
Explicit scope resolution is only necessary in this case:
class A {
public:
void fun(){};
};
class B {
public:
void fun(){};
};
class C : public A , public B
{
};
int main()
{
C c;
c.A::fun();
}
精彩评论