【问题标题】:C++ Headers related to Classes与类相关的 C++ 头文件
【发布时间】:2012-01-28 02:03:18
【问题描述】:

我一直在阅读有关头文件的不同文章和教程。 我了解标头的目的是使“界面”不受实施的影响。 (以及其他一些编译优化)

我仍然不明白,我真的无法理解它,你总是使用标题吗? 我知道您可以在头文件本身中编写代码块。但这就是我迷路的地方。

当我看视频教程时,人们只是在头文件中用他们的主体定义函数。然后另一篇文章只定义了函数(我猜这就是接口的想法)。

现在我正在创建一个名为 Color 的简单类。 实现:

/* 
* File:   Color.cpp
* Author: Sidar
* 
* Created on 26 december 2011, 16:02
*/

#include <stdio.h>

#include "Color.h"

Color::Color() {

 reset();
}

Color::Color(const Color& orig) {

 a = orig.a;
 r = orig.r;
 g = orig.g;
 b = orig.b;
}

void Color::reset()
{
    a = 0;
    r = 0;
    g = 0;
    b = 0;
}

 Color::Color(unsigned int r, unsigned int g, unsigned int b, unsigned int a)
 {
   this->r = r;
   this->g = g;
   this->b = b;
   this->a = a;
 }

Color::~Color() {
   r = 0;
   g = 0;
   b = 0;
 }

 //getters____________________________
 unsigned int Color::getRed() const
 {
   return r;
 }

 unsigned int Color::getBlue() const
 {
   return b;
 }

 unsigned int Color::getGreen() const
 {
    return g;
 }

 unsigned int Color::getAlpha() const
 {
   return a;
 }

 //setters____________________________

 void Color::setRed(unsigned int r)
 {
   if(r > 255)r = 255;
   if(r < 0)r = 0;

   this->r = r;
}


void Color::setGreen(unsigned int g)
{
  if(g > 255)g = 255;
  if(g < 0)g = 0;

  this->g = g;
}

 void Color::setBlue(unsigned int b)
{
   if(b > 255)b = 255;
  if(b < 0)b = 0;

  this->b = b;
}

void Color::setAlpha(unsigned int a)
{
 if(a > 255)a = 255;
 if(a < 0)a = 0;

 this->a = a;
 }

 unsigned int Color::color()
 {
   return (int)a << 24 | (int)r << 16 | (int)g << 8 | (int)b << 0;
  }

这里是标题

/* 
 * File:   Color.h
 * Author: Sidar
 *
 * Created on 26 december 2011, 16:02
 */

 #ifndef COLOR_H
#define COLOR_H
#include <string>

class Color {
public:

    Color();
    Color(const Color& orig);
    Color(unsigned int r,unsigned int g,unsigned int b, unsigned int a);

    virtual ~Color();
    //____________________
    void setRed(unsigned int r);
    unsigned int getRed()const;
    //____________________  
    void setBlue(unsigned int b);
    unsigned int getBlue()const;
    //____________________
    void setGreen(unsigned int g);
    unsigned int getGreen()const;
    //____________________
    void setAlpha(unsigned int a);
    unsigned int getAlpha()const;
    //____________________
    unsigned int color();

   void reset();

private:

    unsigned int r;
    unsigned int b;
    unsigned int g;
    unsigned int a;


};

#endif  /* COLOR_H */

此代码确实有效,我没有收到任何错误。但这是头文件和 cpp 文件的一般概念吗? 我的第二个问题: 我读了很多,当使用模板时,在我理解的 Header 中实现代码会更容易(以防止许多被认为如此通用的东西的实现)。但是还有其他情况吗?

【问题讨论】:

    标签: c++ oop class header


    【解决方案1】:

    您不会“总是”做任何事情,这完全取决于环境、您的目标以及您所在团队或组织的编码标准。

    C++ 是一种非常灵活的语言,它允许以多种不同的方式完成和组织事情。

    可能会使用单独的实现文件的一些原因:

    1. 为了保持实现与接口分离,因为您 建议

    2. 加快编译时间

    3. 处理循环依赖

    4. 因此,您可以发布仅包含头文件而不包含头文件的二进制库 底层源码

    您可能不想要单独的实现文件的一些原因:

    1. 您使用模板,“通常”必须使用 声明

    2. 您不希望实现与接口分离。在 在很多情况下,这会使事情更容易理解,因为您没有 在头文件和实现文件之间来回翻转。这 如果您正在处理大型课程,可能会适得其反 不过方法很多。

    3. 您希望编译器内联尽可能多的代码 可能。

    4. 您正在创建一个代码库,您不希望用户为其创建 不得不担心建筑。大多数 Boost 库是 这样,您就不必使用 Boost 构建系统, 可能很麻烦,但您只需包含头文件 在您的代码中,这就是您使用它们所需要做的一切。


    我通常通过在头文件中定义所有逻辑来开始新类的工作。然后当类完成后,或者当它开始在头文件中变得拥挤时,我将开始将逻辑移出到一个单独的实现文件中。这完全是为了充分利用我的时间,因为当我可以看到同一个文件中的所有内容时,我能够更快地完成工作并且错误更少。

    还应注意,您根本不必使用头文件。您可以直接在 .cpp 文件中定义一些类。这通常适用于永远不会在该 .cpp 文件之外使用的私有类。

    【讨论】:

    • 感谢您的回复。现在更有意义了。我想我只需要在一段时间内做比 Java/C# 更多的 C++ 来适应它。不过,我必须阅读更多关于这些内联函数的内容。
    【解决方案2】:

    好的,首先这里是为什么模板只能在头文件中实现的答案:

    Why can templates only be implemented in the header file?

    这不是因为它是通用的,而是因为编译器实际处理模板的方式。如果你在那里没有得到解释,给我发消息:)。

    【讨论】:

    • 哦,是的,可能说错了,但我理解 =)!
    【解决方案3】:

    如果将方法实现放在头文件中,C++ 编译器可能会选择在调用点内联代码。这样可以更有效率。

    如果您在头文件中完全定义了一个类,那么您不需要 .cpp 文件,使事情(如果实现很短)更容易理解。

    【讨论】:

    • 但是我什么时候需要像我给定的代码一样的 CPP 文件?那是我刚刚打完一个句号的地方。
    • 哈哈,你没有让我更轻松。那么如何做到这一点真的没有标准吗?该约定仅存在于您正在使用的组中?
    • 你可以有cpp的头文件和二进制文件,你不需要源代码来使用它。
    【解决方案4】:

    头文件不用于将接口与实现“分离”,除非您使用 pimpl 习惯用法,否则它们已经包含许多实现细节。那是一个不同的话题,它可以用任何没有“头”文件的语言来完成,比如 C# 和 Java。

    它们的真正用途在于当编译器必须为类的实例分配空间时,它必须知道它的大小。要计算大小,它需要该类的完整声明。由于您可能会在许多翻译单元中使用该类的实例,因此提供该声明的唯一合理方法是将其放入头文件并在需要时#include 它。

    当您创建指向实例(或引用)的指针时,编译器不需要知道该类的大小,因为指针通常具有相同的 4 或 8 字节大小。对于这些情况,您可以只使用前向声明而不是 #include 标头。

    现在,您可以在头文件中包含代码的原因是由于当前的 C++ 模板机制。该代码将被编译多次,但编译器/链接器将消除所有副本并在最终编译的代码中保留一个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      • 2013-09-12
      相关资源
      最近更新 更多