为什么需要明确的范围解析?

时间:2009-12-11 05:43:08

标签: c++ inheritance gcc scope visibility

设定:

class A {
  public:
    void a() {}
};

class B {
  public:
    void b() {}
};

class C: public A, public B {
  public:
    void c() {}
};

我应该做什么(我认为):

C* foo = new C();
foo->b();

我从GCC收到以下链接器错误:

`... undefined reference to 'C::b(void)'`

如果我使用显式范围解析,则可以使用,如:

C* foo = new C();
foo->B::b();

A,B和C共享没有具有相似签名的成员,因此我知道没有任何内容被隐藏。两个问题:

1)理论上,为什么我无法隐式访问公共基类成员?

2)我可以做些什么(如果有的话)来避免这种烦人的语法?

我可以使用显式语法继续开发(虽然我宁愿摆脱它​​)但我更想在这里学习一些关于C ++中公共继承的(显然不正确的)知识。

干杯!

编辑:抱歉,更新了示例代码 - 我原来的一些错误输入错误。

EDIT2:以下是真实代码的(相关部分): 来自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 );
};

来自src / identifier.h:

class Identifiers {
  public:
    Identifiers( void );
    Identifiers( const Identifiers& ref );
    ~Identifiers( void );
};

来自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 );
};

来自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;
}
来自应用程序本身的

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

注意:

1)此处显示的所有方法都在相应的.cpp文件中定义。

2)每个关联的目标文件编译得很好。只有链接器在将所有目标文件链接在一起的最后一步失败。

3)GCC吐出:未定义对`Creature :: remove(Object *)'的引用,除非我通过说明明确限定范围:

creature->Container::remove( *it );

生成文件

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 $@

5 个答案:

答案 0 :(得分:3)

您无法调用未定义的函数。 gcc告诉你的确如此。并且foo::B->b();不是有效的C ++。它不能使用g++cl.exe进行编译。

如果你写了

public:
  void b() {}

它会起作用。

答案 1 :(得分:1)

C foo = new C();
foo->b();

这可能是错的,你可能想要:

C foo;
foo.b();

它应该可以工作,只要你得到的错误不是链接器错误(我不熟悉gcc套件)。如果它是链接器错误,则意味着您的函数没有正文,因此无需调用。

答案 2 :(得分:1)

我认为您发布的任何一个片段都不应该编译。

class C: public A, public B {
  public
    void c();
};

:访问说明符后需要public

C foo = new C();
foo->b();

您正尝试从指向动态分配的C对象的指针初始化C. not ->是在对象类型上调用函数的正确运算符。 ->仅用于指针类型(或具有重载->运算符的对象)。

您需要以下内容:

C foo;
foo.b();

我不确定你所说的片段是如何实际编译的。

答案 3 :(得分:1)

您得到的错误是链接器错误,而不是编译器错误。这意味着您的代码编译 - 很好。链接器抱怨,因为它找不到函数的定义。该定义是否在不同的C ++文件中?也许有一个文件B.cpp包含:

#include "B.h"
void B::b() {
  // do something nifty here
}

然后有一个单独的文件C.cpp,其中包含:

#include "C.h"
C *
func() {
  C* foo = new C();
  foo->b();
  return foo;
}

如果您只编译C.cpp,例如:

g++ -Wall -Wextra C.cpp

然后你会看到你看到的链接器错误。

也许您想要进行部分编译,然后再链接所有.o文件?

g++ -Wall -Wextra -c C.cpp

或许您想将它们全部编译在一起并同时链接?

g++ -Wall -Wextra A.cpp B.cpp C.cpp

答案 4 :(得分:0)

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();

}