我有一个自定义 Stack 实现的示例。据我了解,.h文件应该只包含声明,cpp文件应该只包含implementations。我在cplusplus.com/stack_example上找到了一个自定义堆栈的例子,它看起来像下面这样。
堆栈.h文件
#ifndef _STACK_H_
#define _STACK_H_
#include <iostream>
#include "Exception.h"
template <class T>
class Stack {
public:
Stack():top(0) {
std::cout << "In Stack constructor" << std::endl;
}
~Stack() {
std::cout << "In Stack destructor" << std::endl;
while ( !isEmpty() ) {
pop();
}
isEmpty();
}
void push (const T& object);
T pop();
const T& topElement();
bool isEmpty();
private:
struct StackNode { // linked list node
T data; // data at this node
StackNode *next; // next node in list
// StackNode constructor initializes both fields
StackNode(const T& newData, StackNode *nextNode)
: data(newData), next(nextNode) {}
};
// My Stack should not allow copy of entire stack
Stack(const Stack& lhs) {}
// My Stack should not allow assignment of one stack to another
Stack& operator=(const Stack& rhs) {}
StackNode *top; // top of stack
};
Run Code Online (Sandbox Code Playgroud)
现在我有疑问。这个.h文件显然揭示了一些实现细节。构造函数和析构函数都在文件中实现.h。根据我的理解,这些应该在.cpp文件中实现。此外,还有的是,struct StackNode这也实现了在.h文件中。甚至可以在.cpp文件中实现并只在头文件中声明它吗?作为一般规则,如果这些在.cpp实现文件中不是更好吗?什么是编写这个东西以使其遵循 C++ 规则的最佳方法?
对于头文件中必须包含哪些内容,没有标准规则,标准库头文件除外。我的意思是,从理论上讲,我们可以完全避免头文件以及在文件中复制和粘贴声明。.cpp
也就是说,这更多的是常识和经验的问题。.cpp您可以根据自己的意愿和需要将内容放入 headers 或s 中。我们可以列出一些用例:
模板(如您的示例中所示)声明和实现通常位于标头中。请参阅此线程以获取更多信息。
当您认为/希望函数声明不仅仅用于翻译单元时,您确实可以将函数声明放入标头中
当您不希望/认为函数声明在其他翻译单元中使用时,不要将函数声明放入标头中
如果您想要一个函数inline并希望该函数在不同的翻译单元中使用,那么您可以将其定义放在标头中(inline如果它是非成员函数,则在关键字前面)
当您认为/希望从不同的翻译单元访问该类型的对象时,您确实在标头中放置了类声明(也称为前向声明)
当您认为/希望仅在一个翻译单元中访问该类时,不要将类声明放入标头中
当您认为/希望在不同的翻译单元中创建该类型的对象时,您确实将类定义(即整个类接口)放入标头中
当您希望仅在一个翻译单元中创建该类型的对象时,不要将类定义放入标头中
如果您想定义一个全局变量,您几乎不需要将定义放入头文件中(除非您想将该头包含在单个翻译单元中)
如果您正在开发一个库,您将把想要提供给用户的那些函数和类的声明放入头文件中
.cpp如果您正在开发一个库,您会找到一种方法将您不想公开的实现细节放入文件中(正如 @Joachim Pileborg 建议的那样,请参阅pimpl idiom)
您通常不想将using 声明或using 指令放在标头中,因为它们会污染那些将#include标头包含在内的翻译单元
如果可能的话,您不希望将#include其他标头添加到您的标头中;你肯定更喜欢转发声明你需要什么来让你的程序编译
最后,粗略地说,标头中放入的内容越少,文件的编译速度就越快;而且,让我说显而易见的事情,您确实希望您的文件能够快速编译!
笔记
上面我主要讨论了类和函数,但一般来说,这些经验法则对于枚举和typedef声明都是有效的。
列表中缺少标头中的成员函数定义,因为这是类定义内部或外部的函数定义问题,而不是.hvs.cpp文件的问题
*访问的意思是通过指针或引用使用,与创建的相反
头文件与源文件没有本质区别。
原则上,标头可以包含与源文件相同的代码结构。按照惯例,将标头与源文件区分开来的唯一一件事是标头应该#include被其他文件 d,我们通常不会对源文件这样做(尽管我们可以,如果我们喜欢冒险的话)。
现在重要的是,如果一个文件获取会发生什么#include用d以上的源文件。请注意,这基本上相当于将相同的代码复制粘贴到多个 .cpp 文件中。在这种情况下,有些事情可能会让您陷入困境。
特别是,如果您最终在两个不同的源文件中对同一符号有两个定义,则您的程序格式不正确(根据一个定义规则),链接器可能会拒绝链接您的程序。
对于不同的源文件,这通常不是问题,除非您不小心在不同的上下文中重用了一个名称。一旦头文件进入图片(这只是复制粘贴的代码),事情就开始不同了。您仍然可以将定义放在头文件中,但是如果该头文件随后被多个源文件拉入,则您自己就违反了一个定义规则。
因此,约定是只将内容放入可以安全地跨多个源文件复制的头文件中。这包括声明、内联函数定义和模板。
这里的关键实现可能是头文件是一个相当古老的工具,用于在源文件之间共享代码。因此,他们严重依赖用户足够聪明,不会把事情搞砸。
| 归档时间: |
|
| 查看次数: |
1359 次 |
| 最近记录: |