g ++ неопределенная ссылка в очень простом примере - PullRequest
1 голос
/ 03 октября 2011

Пожалуйста, помогите со следующим вопросом о компиляции и компоновке C ++ и g ++.По сути, у меня есть 2 класса в 2 разных файлах, и я могу скомпилировать их, но когда я пытаюсь связать, один класс не видит методы другого, хотя я связываю оба.Порядок объектных файлов в этом случае не помогает.

Кажется, проблема связана с конструктором не по умолчанию, который принимает параметр.

Я вычеркнул и воспроизвел проблему в следующем простом коде:

Файл: a.cpp :

#include <iostream>

class A
{
  public:
  int my_int;
    A(int i) {
      my_int = i;
      std::cout << "A";
    }
};

Файл: a.hpp:

#ifndef __A_H_
#define __A_H_

class A
{
  public:
  A(int i);
};

#endif

Файл b.cpp:

#include <iostream>

using namespace std;

#include <a.hpp>

class B
{
  public:
  int my_int;
    B(int i) {
      my_int = i;
      A a(i);
      cout << "B\n";
    }
};

int main(int argc, char* argv[])
{
  B b(5);
  cout << "hello world: ";
  cout.flush();
  return 0;
}

Команды, которые я использую для сборки:

g++ -c -I. a.cpp
g++ -c -I. b.cpp
g++ -o c_test a.o b.o

Поочередно я пробовал каждыйиз них:

g++ -o c_test b.o a.o
g++ -I. -o c_test a.cpp b.cpp
g++ -I. -o c_test b.cpp a.cpp

Ошибка, которую я получаю в любом из приведенных выше сценариев ссылок:

b.o: In function `B::B(int)':
b.cpp:(.text._ZN1BC1Ei[B::B(int)]+0x1c): undefined reference to `A::A(int)'
collect2: ld returned 1 exit status

Заранее благодарим за любую информацию.

(извините, если это повторное сообщение - я думал, что опубликовал его и не вижу ...)

Ответы [ 6 ]

3 голосов
/ 03 октября 2011

Так не работает. То, с чем вы столкнулись, технически является нарушением ODR, что примерно означает, что A в a.cpp и b.cpp должно быть одним и тем же. Это не так.

Более того, конструктор неявно inline в a.cpp и, следовательно, его код не нужно выводить.

Изменение a.cpp на

#include <iostream>
#include "a.hpp"

A::A(int i) {
      my_int = i;
      std::cout << "A";
}

исправит ошибку.

1 голос
/ 03 октября 2011

Вы a.cpp нарушаете правило одного определения и полностью переопределяете A.Вы просто хотите определить функцию в вашем исходном файле:

A::A(int i) {
  my_int = i;
  std::cout << "A";
}

Также вы можете пометить функцию как явную, чтобы избежать обработки int s как A в различных нежелательных контекстах..

0 голосов
/ 03 октября 2011

Что нужно сделать, это:

a.hpp

#ifndef __A_H_
#define __A_H_

class A
{
  public:
    int my_int;
  A(int i);
};

#endif

a.cpp

#include <iostream>

#include "a.hpp"

A::A(int i) {
      my_int = i;
      std::cout << "A";
    }

b.cpp - остается прежним

0 голосов
/ 03 октября 2011

Вы нарушаете правило единого определения, поскольку в вашей программе есть два отдельных отдельных класса A.Простая общая реализация вашего файла A.cpp должна выглядеть следующим образом:

#include "a.h" // where the definition of the type is
A::A( int x ) : myint(i) {}

с "ах", содержащим правильное определение типа:

#ifndef A_H_ // identifiers containing double underscores (__) are reserved, don't use them
#define A_H_
class A
{
  int myint; // This must be present in the definition of the class!
public:
  A(int i);
};
#endif;

А затем в реализацииB, вы, вероятно, имели в виду:

#include "a.h"     
#include <iostream>

using namespace std;  // I don't like `using`, but if you use it, do it after all includes!
class B {
public:
//   int my_int;      // do you really want to hide A::my_int??
    B(int i) : A(i) { // use the initializer list
      cout << "B\n";
    }
};
0 голосов
/ 03 октября 2011

У вас есть два разных класса (один содержит myint, другой нет), оба называются class A. Вы не можете сделать это. Изменить a.cpp на:

#include <iostream>
#include "a.hpp"

A::A(int i) {
  my_int = i;
  std::cout << "A";
}

И изменить a.hpp на:

#ifndef __A_H_
#define __A_H_

class A
{
 public:
 int my_int;
 A(int i);
};

#endif

Спасибо за это, как у вас, что будет делать компилятор, если кто-то сделает это:

#include "a.hpp"
// ...
    A foo(3);
    cout << sizeof(foo) << endl;

Как он мог знать, что class A имеет член, отличный от конструктора? Как он мог узнать размер?

0 голосов
/ 03 октября 2011

В a.cpp вы должны #include "a.hpp" и затем определить конструктор просто как A::A(int i) { ... }.Написав полное определение class A с кодом конструктора в теле class, вы неявно определяете конструктор как встроенную функцию, поэтому в объектном файле нет определения для него..

...