草庐IT

c++ - #include 语句应该放在哪里?

coder 2024-02-14 原文

作为 C++ 的新手,我正在尝试整理 #include 方法。

我正在遵循我在下面的示例中详细说明的一组特定指南。到目前为止,这对我来说是可行的(整个项目都在编译 :)),但我担心我将来可能会遇到问题,因此我的问题是 - 这是一种正确的方法吗?有更好的吗?解释它的基本逻辑是什么?

考虑以下示例:

父亲.h

#pragma once
class Father
{
    // Some implementation
};

ClassA.h

#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
    StructC struct_c_obj;
    ClassB class_b_obj;
    // Some implementation
};

ClassA.cpp

#include "Father.h"
#include "ClassB.h"
#include "StructC.h"
// Some implementation

ClassB.hClassB.cpp
没有包含的类

StructC.h

struct StructC {
    // Some implementation
};

我遵循这些准则:

  • 所有 *.h 都以 #pragma once 声明开头
  • 如果ClassA继承自Father类,它必须同时包含在*.h和*.cpp文件中
  • 如果 ClassA 使用 ClassB(并且在类的范围内声明了一个 ClassB 变量),它在 ClassA.h 中有一个 class ClassB; decleration 和一个 #include "ClassB.h" 在 ClassA.cpp 中
  • 如果 ClassA 使用 StructC(并且在类的范围内声明了一个 StructC 变量),它必须将它包含在 ClassA.h 和 ClassA.cpp 中
  • 如果 ClassA 使用 ClassD 或 StructE 但仅在 ClassA.cpp 文件中,那么它应该只在其中包含它们

这可能是一套笨拙的指南,对底层逻辑知之甚少,所以我可能会感到愤怒......来吧,我 尝试在这里学习... :)

更新:

  • 正如一些人在下面所写的,我在这个例子中有一个错误——只有当 ClassA 有一个指针或对 ClassB 的引用时,你才能在 ClassA 中使用 ClassB 的前向声明,而如果它有一个简单的 ClassB 数据成员则不能。

最佳答案

这些是我个人遵循的准则:

  • 尽可能使用前向声明而不是包含。在你的情况下,ClassA包含 ClassB所以#include "ClassB.h"是必须的。有 ClassB类型仅通过指针或引用出现在文件中,前向引用就足够了
  • 使头文件“自给自足”:编译不应该依赖于包含的顺序,并且包含文件应该包含/转发声明所有需要解析的内容
  • 为确保遵守上述准则,请始终包含 ClassA.h第一名 ClassA.cpp ,并对以下内容使用任意排序(我使用的是字母排序)

关于其他方面:

  • #pragma是非标准的,更喜欢include guards
  • 请记住,永远不要转发声明标准类型:if std::string出现在你的头文件中,你#include <string>
  • 如果您最终得到一个包含一百万个其他文件的头文件,您可能需要查看 pimpl idiom减少依赖性(本文还包含其他一些关于头文件的指南)。

关于c++ - #include 语句应该放在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4274755/

有关c++ - #include 语句应该放在哪里?的更多相关文章

  1. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

    我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

  4. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. spring.profiles.active和spring.profiles.include的使用及区别说明 - 2

    转自:spring.profiles.active和spring.profiles.include的使用及区别说明下文笔者讲述spring.profiles.active和spring.profiles.include的区别简介说明,如下所示我们都知道,在日常开发中,开发|测试|生产环境都拥有不同的配置信息如:jdbc地址、ip、端口等此时为了避免每次都修改全部信息,我们则可以采用以上的属性处理此类异常spring.profiles.active属性例:配置文件,可使用以下方式定义application-${profile}.properties开发环境配置文件:application-dev

  7. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  8. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

随机推荐