将 C++ 嵌套类分离到它们自己的头文件中

Posted

技术标签:

【中文标题】将 C++ 嵌套类分离到它们自己的头文件中【英文标题】:Seperating C++ Nested Classes into their Own Header Files 【发布时间】:2021-12-25 01:48:07 【问题描述】:

刚接触这个网站和 C++,但希望得到大家的指导。

我有一个非常有趣的项目想法来学习 C++ 深入挖掘 API、类、引用等,目前我有一个工作示例代码,其中所有内容都存在于 main.cpp 文件中。我面临的问题是,当我将类(内部和外部)移动到它们各自的头文件时,代码不再编译。

嵌套类的原因是 OuterAPI 作为 API 的主要入口点,并且有许多较低级别的 API,然后可以在其下访问(人员、许可证、角色等)。这样,API 用户只需为 OuterAPI 创建一个对象,然后为底层资源和方法创建点符号。

这是 main.cpp 中的工作示例

#include <iostream>
#include <nlohmann/json.hpp>
#include <cpr/cpr.h>
using json = nlohmann::json;

class OuterAPI 
private:
    class InnerAPI 
    private:
        OuterAPI& api;
    public:
        InnerAPI(OuterAPI& a) :api(a) 
        json get() 
            cpr::Response r = cpr::Get(
                cpr::Url api.baseUrl + "resource" ,
                cpr::Bearer api.token 
            );
            return json::parse(r.text)
    ;

    std::string token;
    std::string baseUrl = "";
public:
    InnerAPI people;
    OuterAPI(std::string t) : token(t), people(*this) 
;

int main(int argc, char** argv)

    std::string token = "";
    OuterAPI api(token);
    json jsonData = api.people.get();
    std::cout << jsonData.dump(4) << std::endl;

    return 0;

这是我将所有内容移至相应的头文件/cpp 文件

OuterAPI.h

#pragma once

class OuterAPI 
private:
    class InnerAPI;
    std::string token;
    std::string baseUrl = "";
public:
    OuterAPI(std::string t);
    ~OuterAPI();
    InnerAPI* people;
;

外部API.cpp

#include "WebexAPI.h"
#include "PeopleAPI.h"

OuterAPI::OuterAPI(std::string t) : token(t) 
    people = new InnerAPI(*this);


OuterAPI::~OuterAPI()  delete people; 

InnerAPI.h

#pragma once

#include <nlohmann/json.hpp>
#include <cpr/cpr.h>
#include "OuterAPI.h"

using json = nlohmann::json;

class OuterAPI::InnerAPI 
private:
    OuterAPI& api;
public:
    InnerAPI(OuterAPI& a);
    json get();
;

InnerAPI.cpp

#include "InnerAPI.h"

OuterAPI::InnerAPI::InnerAPI(OuterAPI& a) : api(a) 

json OuterAPI::InnerAPI::get() 
    cpr::Response r = cpr::Get(
        cpr::Url api.baseUrl + "resource" ,
        cpr::Bearer api.token 
    );
    return json::parse(r.text);

main.cpp (finally) - 这是在 api.people.get() "expression must have class type but has type "OuterAPI::InnerAPI *" 处发生编译器错误的地方

int main(int argc, char** argv)

    std::string token = "";
    OuterAPI api(token);
    json jsonData = api.people.get();     // COMPILER ERROR "expression must have class type but has type "OuterAPI::InnerAPI *"
    std::cout << jsonData.dump(4) << std::endl;

    return 0;

据此,我认为问题与我必须将 InnerAPI 对象 people 定义为 OuterAPI 内部的指针有关,但从这里我似乎无法解决。

另外,请随时批评我的设计,就像我说我是 C++ 新手,所以想确保我能做好。谢谢。

【问题讨论】:

“代码不再编译。” 当代码编译失败时,您会收到一条错误消息。该特定信息很重要!它描述了需要解决的问题。你能edit这个问题包含我认为你不理解的错误信息吗? OuterAPI.h 缺少标头保护,它也有 #include 用于它不使用的标头,并且缺少 #include 用于它确实使用的东西。 (在许多 C++ 书籍中,如何组织代码经常被忽视或掩盖。) @DrewDormann,我将编译器错误消息放在“main.cpp”的代码 sn-p 中,但我可以更新为更具体。但是对你来说, api.people.get() 有错误“表达式必须具有类类型但类型为“OuterAPI::InnerAPI *” @Eljay 我确实在头文件的顶部有一次#pragma,只是在代码 sn-p 中错过了它,对此感到抱歉。对包含的良好调用,但即使移动它们似乎也不会改变编译器错误 【参考方案1】:

OuterAPI* 中,您已将people 声明为InnerAPI* 类型的成员。

您可以使用api.people-&gt;get() 调用您的API,也可以将成员设为InnerAPI

编辑:

似乎除了指针之外的错误来自您处理文件包含的方式。我设法得到了working version on REPL.it。我做了一些细微的调整,这样我就不必把两个库都集中在它的要点上。这里是:

OuterAPI.h

#pragma once

#include <string>

class OuterAPI 
private:
    class InnerAPI;
    std::string token;
    std::string baseUrl = "";
public:
    OuterAPI(std::string t);
    ~OuterAPI();
    InnerAPI* people;
;

InnerAPI.j

#pragma once

#include "./OuterAPI.h"

class OuterAPI::InnerAPI 
private:
    OuterAPI& api;
public:
    InnerAPI(OuterAPI& a);
    std::string get();
;

外部API.cpp

#include "./OuterAPI.h"
#include "./InnerAPI.h"

OuterAPI::OuterAPI(std::string t) : token(t) 
    people = new InnerAPI(*this);


OuterAPI::~OuterAPI()  delete people; 

InnerAPI.cpp

#include "./OuterAPI.h"
#include "./InnerAPI.h"

OuterAPI::InnerAPI::InnerAPI(OuterAPI& a) : api(a) 

std::string OuterAPI::InnerAPI::get() 
    return api.baseUrl + "resource";

【讨论】:

感谢您的反馈。我尝试了api.people-&gt;get(),但随后收到错误pointer to incomplete class type "OuterAPI::InnerAPI" is not allowed,您能否详细说明“使成员成为InnerAPI”在实现方面的样子?最初我试图在没有指针的情况下定义people,但由于类型不完整而出现错误。 你只转发声明了吗? (例如:class Foo; 是前向声明,class Foo ; 是定义。 一边测试一边,我意识到您的问题的其余部分可能是您如何在彼此中包含文件。我添加了一份工作草案。 非常感谢,这实际上有助于我现在理解,因为我确实对指针和包含感到困惑。你帮助我确定了一些我必须阅读的领域。我也很感谢您花时间对此进行测试。我测试了一个也能够让代码正确编译。如果我可以再问一个关于包含的问题,对于main.cpp,我必须同时包含Outer.hInner.h 才能使其正常工作。是否有解决方案只允许将 Outer.h 文件包含在 main 中? 明白。非常感谢所有的帮助【参考方案2】:

确保在您打算这样做的每个文件中都包含您打算使用的所有内容。 将声明和定义分开是很常见的。 这是一种减少大型项目编译时间的方法。 谢天谢地,modules 很快就会™ 让链接成为过去。

要解决错误消息:您将people 声明为OuterAPI 类的原始成员指针...您无法通过使用operator . 的指针访问成员,您需要使用operator -&gt;

【讨论】:

我要感谢您 ViralTaco_ 的帮助。

以上是关于将 C++ 嵌套类分离到它们自己的头文件中的主要内容,如果未能解决你的问题,请参考以下文章

QT中头文件带不带.h的问题

C++中CTime的头文件

C++中头文件<ctime>包含哪些函数

VS2015--win32工程配置的一些想法之Google Code Style中头文件的顺序

C++中头文件与源文件的作用详解

(通俗易懂的)C++中头文件与源文件的作用详解