【问题标题】:Can I forward-declare names -defined in other header in a header files?我可以在头文件的其他头中前向声明名称吗?
【发布时间】:2020-05-07 17:01:46
【问题描述】:

我想创建一个类 Student,它有一个类型库 std::string 的成员,但我不想在我的 Student.h 中包含标题 <string> 并且只使用前向声明:

// Student.h
#ifndef STUDENT_H
#define STUDENT_H

#include <iostream>

typedef class string_ string;

struct Student
{
public:
    Student(const string_&, std::size_t);
    const string_ name()const;
    void setName(const string_&);
    std::size_t age()const;
    void setAge(std::size_t);
private:
    string_* name_ ;
    std::size_t age_;
};

 // Student.cpp
#include "Student.h"
#include <string>

Student::Student(const std::string& str, std::size_t a) :
    name_(&str),
    age_(a)
{}
  • 编译程序时出现以下错误:../src/Student.cpp:13:2: error: no declaration matches ‘Student::Student(const string&, std::size_t)’ 13 | Student::Student(const std::string& str, std::size_t a) :

  • 那么我是否可以使用前向声明,以便在标头中不包含任何标头,而只是前向声明我需要的类型,然后在源中包含标头?

  • 我这样做是因为我正在阅读 Guillaume Lazar 的 Mastering Qt5 一书,他在其中给出了这个例子:

    //SysInfoWindowsImpl.h
    #include <QtGlobal>
    #include <QVector>
    #include "SysInfo.h"
    
    
    typedef struct _FILETIME FILETIME;
    
    class SysInfoWindowsImpl : public SysInfo
    {
    public:
        SysInfoWindowsImpl();
        void init() override;
        double cpuLoadAverage() override;
        double memoryUsed() override;
    private:
        QVector<qulonglong> cpuRawData();
        qulonglong convertFileTime(const FILETIME& filetime) const;
    private:
        QVector<qulonglong> mCpuLoadLastValues;
    };
    
    //SysInfoWindowsImpl.cpp
    #include "SysInfoWindowsImpl.h"
    #include <windows.h>
    
    
    SysInfoWindowsImpl::SysInfoWindowsImpl() :
        SysInfo(),
        mCpuLoadLastValues()
    {
    }
    
    void SysInfoWindowsImpl::init()
    {
        mCpuLoadLastValues = cpuRawData();
    }
    
    qulonglong SysInfoWindowsImpl::convertFileTime(const FILETIME& filetime) const
    {
        ULARGE_INTEGER largeInteger;
        largeInteger.LowPart = filetime.dwLowDateTime;
        largeInteger.HighPart = filetime.dwHighDateTime;
        return largeInteger.QuadPart;
    }
    

"语法typedef struct _FILETIME FILETIME是一种转发 FILENAME 语法的声明。由于我们只使用参考,我们可以避免 在我们的文件 SysInfoWindowsImpl.h 中包含标签并保留它 在 CPP 文件中。”来自书中。

  • 那么有人可以向我解释他如何使用在windows.h 中定义的typedef struct _FILETIME 吗?谢谢。

【问题讨论】:

  • typedef class string_ string; - 这不是前向声明。而且我会回避这样的别名。他们会在某个时候咬你。
  • @JesperJuhl:我在 Qt 书中看到过这样的例子:typedef struct _FILETIME FILETIME; 你觉得怎么样?
  • 我想我不知道你在问什么。你明白那行代码是做什么的吗?您是在问为什么这在 Qt 中有意义吗?您是否只是复制'n'粘贴您在其他地方看到的东西,希望它能解决您的问题,但没有真正理解它(我目前的猜测)?

标签: c++ forward-declaration


【解决方案1】:

是的,但前提是它们匹配。

您转发声明了一个全局类型string,而不是在命名空间std中。

您可能可以使其与namespace std {} 一起工作,但是您的程序将具有未定义的行为,因为您不允许在该命名空间中声明新事物(有一些例外)。

一般来说,您希望避免对除您自己的类之外的任何内容进行前向声明。

只需#include &lt;string&gt;。如果这样做会导致问题,您应该独立解决这些问题。

【讨论】:

  • 为什么在 Qt5 的书中他转发声明 typedef struct _FILETIME FILETIME; which is defined in windows.h` 标题? `
  • @Maestro:(A) 因为FILETIME 在全局命名空间中,而不是在std 命名空间中,所以它可以工作,并且(B) 因为你可以在全局命名空间。你不能在 std 命名空间中声明东西
  • @MooingDuck:你的意思是FILETIME 不是FILENAME
  • 是的,很抱歉我的错字
  • @MooingDuck:谢谢。
【解决方案2】:

不,您今天不能(2020 年 5 月)。另请参阅 thisn3337(C++11 标准)。

但 C++20 或更高版本可能会添加modules,然后情况就不同了。

实际上,对于一个小程序(例如,少于几十万行你的 C++ 代码),一种常见的方法是使用一个单独的头文件 - #include 在您的每个 translation units, 中,并且该公共主头文件将 #include 许多标准头文件。对于最近的GCC,您可以使用precompiled headers(实际上,使用单个主头文件效果最好,也许#include -ing 子头文件;请参阅this 解释)

考虑使用足够好的build automation 工具集。在 Linux 上,这可能是 GCCClangccachemakeninja 等的组合...

【讨论】:

  • 我不认为推荐一个“神头”是个好主意。即使是小型项目。它会导致懒惰地只包括你使用的东西,小项目往往会随着时间的推移而变大,然后坏习惯开始变得糟糕,需要大量的努力来清理。
  • @Jesper Juhl:大文件有什么问题?我通常有超过 10 个 KLOC 的文件,如果我查看 GCC 的源代码,他们也在这样做。我的一些 C 或 C++ 文件已生成,它们可能更大。当然,你需要一个足够好的编辑器(比如emacs
  • 我已经编辑了主题,你想看看吗?谢谢
  • @BasileStarynkevitch 问题不在于大文件。问题在于许多文件包括比他们需要的更多的标题。我从事的项目过去需要大约 20 分钟才能在具有 HT 的 20 核 Xeon CPU 上进行编译。当我们努力减少无意义的包含时,时间下降到大约一半(是的,这很糟糕,很多上帝的标题等)。
  • @BasileStarynkevitch 我从源代码构建了 Qt。很多次。是的,这很慢,但是这与通过包含无意义的东西来降低构建速度有什么关系呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多