таинственная ошибка компоновщика - PullRequest
1 голос
/ 06 июня 2011

Я написал простую программу, которая использует некоторые классы и буферы прокола. Эти классы упрощают подключение и отправку сообщений между компьютерами. Компиляция прошла успешно. Тем не менее, линкер говорит:

server.o: в функции `main ':

server.cpp :(. Text + 0x24): не определено ссылка на `DataExchange :: Server :: Сервер (без знака int) '

.

server.cpp :( текст + 0x39): неопределенная ссылка на `DataExchange :: Server :: принимает ()

server.cpp :(. Text + 0x51): не определено ссылка на `DataExchange :: Подключение :: получить () collect2: ld вернул 1 статус выхода

код: server.cpp:

#include <iostream>

#include "connection.h"
#include "protocol.pb.h"

using namespace std;
using namespace msg;
using namespace dataExchange;

int main() {
  Server server(1234);
  while(1) {
    Connection con = server.accept();
    Annoucement ann = con.receive();
    cout << ann.typ() << endl;
  }
}

connection.h:

namespace dataExchange {

  class SocketMaintenance {
  protected:
    sockaddr_in addr;
    int s;
  public:
    SocketMaintenance(const unsigned int) throw();
    SocketMaintenance(const sockaddr_in, const int) throw();
    SocketMaintenance(const SocketMaintenance&) throw();
    ~SocketMaintenance();
    void write(const char*, const int);
  };

  class Connection {
    FileOutputStream* raw_output;
    FileInputStream* raw_input;
    char buffer[1024];
  public:
    Connection(const char*, const unsigned int);// throw(WrongAddress);
    Connection(const SocketMaintenance&);//throw(ConnectFailed);
    void send(const Message&) throw();
    Annoucement receive() throw();
  };

  class Server {
  public:
    Server(const unsigned int);// throw(BindFailed,ListenFailed);
    Connection accept() throw();
  };

}

В чем причина сбоя компоновщика?


порядок строительства:

g ++ server.cpp -c; g ++ protocol.pb.cc -c; g ++ connection.cpp -c; g ++ server.o protocol.pb.o connection.o -lprotobuf

conection.cpp

using namespace std;
using namespace msg;
using namespace google::protobuf;
using namespace google::protobuf::io;

namespace dataExchange {

  class SocketMaintenance {
  protected:
    sockaddr_in addr;
    int s;
  public:
    SocketMaintenance(const unsigned int port) {
      memset(&addr, 0, sizeof(addr));
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      s = socket(AF_INET, SOCK_STREAM, 0);
    }
    SocketMaintenance(const sockaddr_in Addr, const int Socket) {
      addr = Addr;
      s = Socket;
    }
    SocketMaintenance(const SocketMaintenance& source) {
      addr = source.addr;
      s = source.s;
    }
    ~SocketMaintenance() {
      close(s);
    }
    void write(const char* buffer, const int n) {
      ::write(s, buffer, n);
    }
  };

  class Connection : public SocketMaintenance {
    FileOutputStream* raw_output;
    FileInputStream* raw_input;
    char buffer[1024];
  public:
    Connection(const char* IP, const unsigned int port) : SocketMaintenance(port) {
      if(inet_pton(AF_INET, IP, &addr.sin_addr)<=0) {
    throw WrongAddress();
      }
      if(connect(s, (sockaddr*)&addr, sizeof(addr))<0) {
    throw ConnectFailed();
      }
      raw_output = new FileOutputStream(s);
      raw_input = new FileInputStream(s);
    }
    Connection(const SocketMaintenance& source) : SocketMaintenance(source) {}
    ~Connection() {
      delete raw_output;
    }
    void send(const Message& msg) throw(EmptyMessage)  {
      CodedOutputStream* coded_output = new CodedOutputStream(raw_output);
      int n = msg.ByteSize();
      if(n<=0) throw EmptyMessage();
      coded_output->WriteVarint32(n);
      delete coded_output;
      raw_output->Flush();
      msg.SerializeToArray(buffer, n);
      SocketMaintenance::write(buffer, n);
    }
    Annoucement receive() throw() {
      CodedInputStream* coded_input = new CodedInputStream(raw_input);
      google::protobuf::uint32 n;
      coded_input->ReadVarint32(&n);
      char *b;
      int m;
      coded_input->GetDirectBufferPointer((const void**)&b, &m);
      Annoucement ann;
      ann.ParseFromArray(b, n);
      return ann;
    }

  };

  class Server : public SocketMaintenance {
  public:
    Server(const unsigned int port) : SocketMaintenance(port) {
      addr.sin_addr.s_addr = htonl(INADDR_ANY);
      if(bind(s, (struct sockaddr *)&addr, sizeof(addr))<0) {
    throw BindFailed();
      }
      if(listen(s, 5)<0) {
    throw ListenFailed();
      }
    }
    Connection accept() throw() {
      sockaddr_in client;
      socklen_t client_len;
      int client_socket = ::accept(s, (sockaddr*)&client, &client_len);
      return Connection(SocketMaintenance(client, client_socket));
    }
  };

}

Ответы [ 3 ]

4 голосов
/ 06 июня 2011

Забыл скомпилировать и / или связать "connection.cpp", скорее всего. Я хотя бы надеюсь, что у вас есть такой файл, который реализует все функции?


Я думаю, у вас есть некоторые фундаментальные недоразумения, как работает разбиение в .h и .cpp. В .cpp вы не просто заново объявляете классы, на этот раз с функциями, определенными внутри них. Вам нужно сделать так:

// connection.cpp
namespace dataExchange{
// define the constructor of Server
Server::Server(const unsigned int port)
  : SocketMaintenance(port)
{
  // ....
}

// define the accept function of Server
Connection accept() throw(){
  // ...
}
// ...
}

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

1 голос
/ 06 июня 2011

Когда вы #include "connection.h", вы получаете объявления методов Server. Это в основном сообщает компилятору, какие методы существуют, и позволяет компиляции завершиться успешно.

Чтобы связать ваш исполняемый файл, вам нужно связать с определениями этих методов (то есть с реальным кодом, который их реализует). Для классов, определенных в connection.h, они обычно находятся в файле с именем connection.cpp или аналогичном. Вам нужно скомпилировать этот файл и указать результирующий объектный файл во время шага ссылки.

0 голосов
/ 06 июня 2011

В вашем проекте должен быть файл connection.cpp, который реализует конструктор Server::Server(const unsigned int).У тебя это есть?

Вы также можете помочь себе и вставить команду, которую вы вводите для компиляции, возможно, вам не хватает файла для связи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...