如何在与主函数不同的源文件中定义类?

时间:2019-01-24 03:50:14

标签: c++

这应该是很偶然的,我只是想不出如何将源代码分成不同的文件。

当我将代码编写为单个源文件时,我的代码可以编译并执行得很好:

#include <iostream>
using namespace std;

class Greeter{ 
    public:
        void greet();
};

void Greeter::greet(){
    cout << "Hello World!";
}

int main(){
    Greeter greeter;
    greeter.greet();
    return 0;
}

但是请尝试将代码分成单独的源文件:

Greeter.h

#include <iostream>
using namespace std;

class Greeter{ 
    public:
        Greeter();
        void greet();
};

Greeter.cxx

#include <iostream>
#include "Greeter.h"
using namespace std;

void Greeter::greet(){
    cout << "Hello World!";
}

main.cxx

#include <iostream>
#include "Greeter.h"
using namespace std;

int main(){
    Greeter greeter;
    greeter.greet();
    return 0;
}

总是会导致编译错误:

main.cxx:(.text+0x16): undefined reference to `Greeter::Greeter()'

1 个答案:

答案 0 :(得分:4)

目前尚不清楚这些评论是否解决了您的问题。在将源分成标题和多个源时,该错误证明的主要问题是,您在class Greeter中包含了Greeter.h的不完整构造函数。具体来说,您无法包含“空参数列表” 来完成构造函数,例如

    Greeter() {};   /* default construct */

请参见cppreference - Default constructors

您应避免的下一个问题是在头文件中包含using namespace std;。参见“using namespace” in c++ headers。相反,只需调用coutstd::cout,而无需完全包含名称空间。

接下来,尽管iostream具有适当的标题保护,但您只需要将其包括在Greeter.cpp中(这是唯一使用iostream函数的源)。您还应该在Greeter.h中包括标头保护符,以防止在编译过程中包含多个内容。只需创建一个#define并检查是否已经在标头中定义了该标头,例如

greeter.h

#ifndef my_class_greeter_h
#define my_class_greeter_h  1

class Greeter { 

    public:
        Greeter() {};   /* default construct */
        void greet();
};

#endif

现在,如果已经定义了greeter.h,则每个包含my_class_greeter_h的文件都将避免再次包含它。

greeter.cpp

带有类函数定义的源文件是唯一依赖iostream调用的源文件,并且是唯一需要#include <iostream>的文件,例如

#include <iostream>

#include "greeter.h"

void Greeter::greet(){
    std::cout << "Hello World!\n";
}

main.cpp

main.cpp源文件只需要包含包含类定义的标头,例如

#include "greeter.h"

int main (void) {

    Greeter greeter;    /* instantiate greeter */
    greeter.greet();    /* call greet() */

    return 0;
}

两个源都必须编译

要编译单独的源文件,需要同时编译main.cppgreeter.cpp(编译greeter.cpp以使其成为对象,或者仅将两个.cpp文件都包含在编译字符串中)

使用gcc/clang

进行编译
$ g++ -Wall -Wextra -pedantic -std=c++11 -Ofast -o main main.cpp greeter.cpp

使用VS(cl.exe)编译

> cl /nologo /W3 /Ox /EHsc /Femain /TP main.cpp greeter.cpp

(在没有警告的情况下编译之前,不接受代码)

使用/输出示例

在任何一种情况下,输出均符合预期:

$ ./main
Hello World!

仔细检查一下,如果还有其他问题,请告诉我。