我应该在哪里实现我的类方法?

时间:2015-02-02 17:45:21

标签: c++

我知道三种不同的实施方式"位置"对于我的班级方法:

1)在我的类(.h文件)中定义方法并在我的.cpp文件中实现它

//.h
class Foo
{
  int getVal() const;
};


//.cpp
int Foo::getVal() const
{ return 0; }

2)在我的类(.h文件)中定义并实现该方法。

//.h
class Foo
{
  int getVal() const
  { return 0; }
};

3)在我的类中定义方法,并在类外但在我的头文件中实现它。

//.h
class Foo
{
  int getVal() const;
};

int Foo::getVal() const
{ return 0; }

这三种方法有哪些主要区别?

3 个答案:

答案 0 :(得分:9)

这个问题有三个要素:可读性(代码看起来有多好),编译(编译器可以优化多少)和实现隐藏(如果将代码用作库,则可能不希望显式共享你和世界的特别酱油。

方法一只公开头文件中函数的接口。这意味着您将显示一个漂亮的干净界面,并且您的实现不会以纯文本形式公开。但是,代码不能跨编译单元内联,因此它有可能在运行时稍慢(实际上,这仅对非常非常非常小的代码百分比很重要)。这应该是你的默认方式。

方法2是隐式内联。冗长的功能会让你的课程变得混乱,因为(imho)很糟糕。同时将您的实现暴露给全世界。但是,该函数可以内联,并且比在另一个地方定义它更简洁。我保留这个非常小的功能。

方法3实际上是非法的,因为您将破坏单定义规则,但以下情况很好:

//Foo.h
class Foo {
  int getVal() const;
};

inline int Foo::getVal() const { 
  return 0; 
}

当我想保持类定义干净但想要头文件中的函数定义(对于inlinable或模板函数)时,我使用它。

答案 1 :(得分:2)

(1)将为一个大项目编译得更快(只需要在Foo.cpp中编译getVal一次的定义,并且只需要在定义更改时重新编译一件事),并且你得到一个非常明确的一个类的接口,供想要查找的人使用。另一方面,您无法内联getVal()

(2)和(3)将编译得更慢,并为您的定义更改添加更多依赖项。但是你可以内联getVal()。如果getVal是模板函数,则还需要这样做。如果您的标题被多次包含,注意(3)将导致链接器错误 - 您必须标记记住标记您的函数inline。这是偏好(1)和(2)到(3)的一个很好的理由。

真的不是挑选(1)vs(2)。您可能会在大型项目中使用它们 - 在头文件中放置应该内联的函数的定义(和模板),并在cpp中放置内联不太合理的内容。

答案 2 :(得分:1)

在我开始之前的一个小注释,有很多用于描述这些内容的非常类似的单词,我将使用头文件中的部分声明(int getVal() const)和部分的实现cpp文件(int Foo::getVal() const)。如果这些不完全准确,请道歉。

另请注意,如果不明确,则其他人将受到处罚。

  

1)在我的类(.h文件)中定义方法并在我的.cpp文件中实现它

这被认为是标准方法,并且通常被认为是默认方法(有很多例外,因此默认可能有点强)。

它将声明与实现分开。这提供了一些好处:

  • 您只需要编译一次实现。这可能会节省编译时间。
  • 您只需要参考声明即可。这可以避免排序问题,对于类之间的循环引用至关重要。
  • 您不会分发您的实施,这对于闭源系统很有用,因为您经常需要分发大量的.h文件,以便其他人插入您的系统。
  

2)在我的类(.h文件)中定义并实现该方法。

这称为内联实现,只应在简单实现中使用。它也有一些好处:

  • 大多数编译器将此视为一个巨大的内联提示。它不保证inling但很可能,对于简单的方法可能是一个胜利。属性样式方法是一个常见的例子。
  • 您的实施很容易找到,因为它直接在声明中。
  

3)在我的类中定义方法,并在类外但在我的头文件中实现它。

我之前没有看过这个,但是假设它在定义非平凡时使用,但你希望内联的好处是2. IdeaHat提到inline关键字是必需的这种情况。