【问题标题】:How to implement a member function in a different header file?如何在不同的头文件中实现成员函数?
【发布时间】:2020-07-22 14:35:25
【问题描述】:

[更新] 一个可重现的例子

通过将声明和定义分成不同的文件,我的玩具代码构建没有问题......

我的 main.cpp

#include <iostream>
#include "file0.h"
#include "file1.h"
#include "file2.h"

int main() {
    test a;
    double b = a.get_recipocal(2.0);
    double c = a.get_sqrt(2.0);
    std::cout << "b = " << b << std::endl;
    std::cout << "c = " << c << std::endl;
    return 0;
}

我的文件0.h

#ifndef TEST_MULTI_FILES_FILE0_H
#define TEST_MULTI_FILES_FILE0_H

class test {
private:
    double a;
public:
    double get_recipocal(int a);
    double get_sqrt(int a);
};


#endif//TEST_MULTI_FILES_FILE0_H

我的文件1.h

#ifndef TEST_MULTI_FILES_FILE1_H
#define TEST_MULTI_FILES_FILE1_H

double test::get_recipocal(int a) {
    return 1. / a;
}

#endif//TEST_MULTI_FILES_FILE1_H

我的文件2.h

#include <cmath>
#ifndef TEST_MULTI_FILES_FILE2_H
#define TEST_MULTI_FILES_FILE2_H

double test::get_sqrt(int a) {
    return sqrt(a);
}

#endif//TEST_MULTI_FILES_FILE2_H

构建并运行没有问题。所以这不是我的生产代码中的明显错误

谢谢!

(以下是原始问题) 我是 C++ 类的新手,这是我的问题

例如,我在文件b0.h中有一个类

class B::virtual public A {
  void func1() {
    some work1;
  }
  void func2() {
    some work2;
  }
  ...
};

现在我想将func2() 的实现移动到另一个头文件中,比如b1.h 所以我做了以下事情:

#include "path/to/b0.h"
void B::func2(){
  some work2;
}

但是编译器会报错

use of undeclared identifier 'B'
void B::func2() {
     ^ 

(我还测试了以下内容:在b0.h 中,我包含了b1.h,如果我在b1.h 中将func2() 设为静态函数,我可以毫无问题地从b0.h 调用它。)

目标是将B的成员分成两个头文件,每个头文件包含一个函数实现(我想在不同文件中比较func1和func2,它们相似且很长)。我觉得这是一个很常见的场景,但是我没有找到一个很好的例子。有明显的错误吗?谢谢!

【问题讨论】:

  • 我认为您的示例代码不足以发现显示的错误。尽管您的代码有 func2() 的 2 个定义
  • 你为什么在头文件而不是翻译单元/源文件中实现类成员?
  • @drescherjm 这对我来说还不清楚,但整个包装都是这样的,所以我认为没关系。
  • class B::virtual public A { 应该是 class B : virtual public A {。并且您的函数需要返回类型,并且标头应该只包含声明(没有函数体)。定义转到源文件。所有这些在一些good C++ books中都有更详细的解释。
  • 可以按照您的要求做,但这是糟糕的设计。如果整个包装都是这样的,那它仍然是糟糕的设计,你不应该遵循它。

标签: c++ class header-files member-functions


【解决方案1】:

如果你有更大的班级,你想做的事情是很常见的。你需要的是 一个 带有 all 声明的头文件,比如b.h:

#include "path/to/a.h"

class B : virtual public A { // : instead of :: 
  void func1(); // return type, no function body
  void func2(); // return type, no function body
};

然后,您可以将定义(实际实现)拆分为任意数量的源文件。例如文件b_func1.cpp 可能包含B::func1 的定义

#include "path/to/b.h"

void B::func1() { /* some code */ }

文件b_func2.cpp 可能包含B::func2 的定义

#include "path/to/b.h"

void B::func2() { /* some code */ }

无论如何,只有在特定情况下(如模板或内联函数),定义才可以在标题中。只要你只包含每个标题一次,它就可以工作,但它仍然是错误的,所以将定义放在翻译单元/源文件中。

【讨论】:

  • 好的。让我试试 func2,因为 func1 已经存在于包中,我不想更改结构。但是,我担心即使我将原始文件包含在新文件中,当我尝试在新文件中调用其成员函数时,类 B 仍然是一个不清楚的标识符。看起来 B 类没有正确包含...
  • @yue 也许你有一个循环包含,你没有在你的示例代码中显示。鉴于当前的示例代码,这个错误来自哪里还不是很清楚。
  • @yue 查看您发布的其他 sn-ps,您可能需要对 include 进行一些说明。这些 sn-ps 之所以起作用,是因为 a)您以正确的顺序包含它们,这样声明就在定义之前,并且 b)您只包含每个文件一次。但这不是好的项目结构,会造成太多的陷阱。不要在标题中放置任何定义(除非您需要,如前所述,但您不需要在此处执行此操作。)这些 sn-ps 的工作在剃须刀边缘上是平衡的,它不会像这样工作任何真正的代码库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 2018-10-12
  • 1970-01-01
  • 2021-06-02
  • 2022-01-12
  • 2022-01-05
相关资源
最近更新 更多