C++ 11 如何在其他 classes 或源文件中引用 class 方法

C++ 11 How to reference class methods in other classes or source files

经过几年的概念验证,我又回到了 C++。我有一个定义 class 的 hpp 文件、一个带有 class 方法的 cpp 文件和一个用于测试的 main.cpp。我正在尝试创建一个在自己的线程中运行的 tcp 服务器(只调用一次)。我从同一个 cpp 文件中的所有代码开始,并让它工作,但现在我收到编译错误,因为我已经将 class 和方法放在它们自己的文件中。

我已经搜索过但没有找到任何有用的东西。我试过使用 extern、'singleton' 方法等,它们都会导致各种错误消息。我知道我没有提供对这些方法的正确参考。

tcpserver.hpp:

#ifndef __TCP_SERVER_HPP_INCLUDED__   
#define __TCP_SERVER_HPP_INCLUDED__   

#include <string>

class Server {
    public:

        static void *tcp_server(void * dummy);
        static void hello();
        static int parseCmd(const char *cmd, char *reply);
        static int copystring(char *reply, const char *msg);

    private:

};

#endif

tcpserver.cpp,class 方法作为存根:

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
#include <cstring>      // Needed for memset
#include <sys/socket.h> // Needed for the socket functions
#include <netdb.h>      // Needed for the socket functions
#include <string.h>

#include "tcpserver.hpp"

int Server::parseCmd(const char *cmd, char *reply) {
   //does stuff 
}   


int Server::copystring(char *dst, const char *src) {
    // does stuff
    return (int) ((std::string) dst).length();
}


void Server::hello() {
    std::cout << "Server says 'hello'." << std::endl;
}


void *Server::tcp_server(void * dummy) {
    const char *port = "5555";
    // does a lot of stuff
}

main.cpp:

#include <iostream>
#include <pthread.h>

#include "tcpserver.hpp"

int main() {
    Server server;
    server.hello();  // 'Canary' method FIRST ERROR 

    // Initialize and set thread joinable
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    pthread_t serverthread;
    int rc;
    // **** tcp_server method must be static ****
    rc = pthread_create(&serverthread, NULL,  server.tcp_server, NULL);
        if (rc){
          std::cout << "Error:unable to create thread," << rc << std::endl;
          exit(-1);
        }
    std::cout << "Main() started thread."  << std::endl;
    pthread_attr_destroy(&attr);
    void *status;
        rc = pthread_join(serverthread, &status);
        if (rc){
          std::cout << "Error:unable to join," << rc << std::endl;
          exit(-1);
        }


    return 0 ;
}

makefile:

all :  main.o tcpserver.o
    g++ -std=c++11 -o tcpserver main.o tcpserver.o 

tcpserver.o: tcpserver.cpp tcpserver.hpp
    g++ -std=c++11 tcpserver.hpp

main.o  : main.cpp tcpserver.hpp
    g++ -std=c++11 main.cpp -lpthread

clean: 
    rm -f tcpserver.o main.o tcpserver

你的目标文件编译不正确:

tcpserver.o: tcpserver.cpp tcpserver.hpp
    g++ -std=c++11 tcpserver.hpp

main.o  : main.cpp tcpserver.hpp
    g++ -std=c++11 main.cpp -lpthread

这些规则并不表示您正在构建目标文件,它们都表示它们正在独立构建和 linking 应用程序。这就是为什么您会收到 linker 错误 - 您实际上并没有 linking 编译 main.cpptcpserver.o 的结果。

您需要提供 -c 来告诉 gcc 您不想 link,您 只是 编译。您还需要提供 -o 来告诉它在哪里输出结果。最后,您尝试编译 tcpserver.hpp 而不是 tcpserver.cpp:

tcpserver.o: tcpserver.cpp tcpserver.hpp
    g++ -std=c++11 -c tcpserver.cpp -o tcpserver.o

main.o  : main.cpp tcpserver.hpp
    g++ -std=c++11 -c main.cpp -o main.o

或者,更短:

%.o : %.cpp tcpserver.hpp
    g++ -std=c++11 -c $< -o $@

此外,这条规则是错误的:

all :  main.o tcpserver.o
    g++ -std=c++11 -o tcpserver main.o tcpserver.o

规则的目标是 all,但它实际上是在创建一个名为 tcpserver 的文件。因此,如果您继续重新运行 make,它将继续重建 tcpserver,因为文件 all 将继续不存在。更改目标以匹配实际目标。这就是你的 linker 旗帜所在的地方:

tcpserver :  main.o tcpserver.o
    g++ -std=c++11 -o tcpserver $^ -lpthread

此外,您使用的包含防护 (__TCP_SERVER_HPP_INCLUDED__) 是 C++ 标准库的保留名称。任何包含双下划线或以下划线后跟大写字母开头的名称都不应在您的代码中使用。

如前所述,这是一个编译问题,-lpthread在错误的地方。

我建议使用更简单的 Makefile,利用默认规则、依赖项等,并设置各种警告

CXXFLAGS = -std=c++11 -Wall -Wextra -pedantic
LDFLAGS = -lpthread

tcpserver: main.o tcpserver.o
    $(LINK.cc) $^ -o $@

clean: 
    rm -f tcpserver.o main.o tcpserver

# DO NOT DELETE

main.o: tcpserver.hpp
tcpserver.o: tcpserver.hpp

注意:关于依赖关系的最后 4 行(以 DO NOT DELETE 开头)已通过命令自动添加到 Makefile 中

makedepend -Y *.cpp

这些警告将有助于修复错误:

 tcpserver.cpp: In static member function ‘static int Server::parseCmd(const char*, char*)’:
    tcpserver.cpp:14:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }   
 ^
tcpserver.cpp: At global scope:
tcpserver.cpp:12:34: warning: unused parameter ‘cmd’ [-Wunused-parameter]
     int Server::parseCmd(const char *cmd, char *reply) {
                                      ^
tcpserver.cpp:12:45: warning: unused parameter ‘reply’ [-Wunused-parameter]
     int Server::parseCmd(const char *cmd, char *reply) {
                                             ^
tcpserver.cpp:17:47: warning: unused parameter ‘src’ [-Wunused-parameter]
     int Server::copystring(char *dst, const char *src) {
                                                   ^
tcpserver.cpp: In static member function ‘static void* Server::tcp_server(void*)’:
tcpserver.cpp:29:17: warning: unused variable ‘port’ [-Wunused-variable]
     const char *port = "5555";
                     ^
tcpserver.cpp:31:1: warning: no return statement in function returning non-void [-Wreturn-type]
     }
     ^
tcpserver.cpp: At global scope:
tcpserver.cpp:28:33: warning: unused parameter ‘dummy’ [-Wunused-parameter]
     void *Server::tcp_server(void * dummy) {