在哪里放置函数声明?

Where to put function declaration?

本文关键字:声明 函数 在哪里      更新时间:2023-10-16

假设我正在开发一个日志记录功能。在logging.h里面,我声明了应用程序稍后要使用的函数。

// logging.h
#include <string>
namespace logging {
void LogThis(const std::string& text);
};  // namespace logging

它的定义显然在logging.cpp里面:

// logging.cpp
void logging::LogThis(const std::string& text) {
std::cout << "Log: " << text << 'n';
}

现在让我们假装我的LogThis函数的工作被拆分为一些较小的帮助程序函数。它们不是日志记录接口的一部分。让我们以Prettify函数为例。

// logging.cpp
void logging::LogThis(const std::string& text) {
Prettify(text);
std::cout << "Log: " << text << 'n';
}

我的问题是:我把Prettify的函数声明放在哪里?我不应该将它包含在logging.h头文件中,因为这样它就可以被其他编译单元调用,并且它不是接口的一部分。所以就这样把它放在logging.cpp里面吗?

// logging.cpp
namespace logging {
void Prettify(std::string& ugly_text);
void LogThis(const std::string& text) {
Prettify(text);
std::cout << "Log: " << text << 'n';
}
void Prettify(std::string& ugly_text) {
// making it pretty...
}
}

我正在寻找一些关于此:)的最佳实践/经验法则/意见提前感谢!

对于文件中只需要的东西,我只是将其放在C++文件本身的匿名命名空间中,有点像 functions(a(上的旧版 Cstatic关键字的现代等价物:

namespace {
void WeaveMagic(std::string& ugly_text) {
WeaveMoreMagic(ugly_text);
}
void Prettify(std::string& ugly_text) {
WeaveMagic(ugly_text);
}
}

如果在使用函数之前放置此值,并确保调用的严格层次结构,则可以跳过声明,因为定义提供了所需的信息,如上所示。

当然,如果多个匿名函数之间存在任何循环依赖关系(即循环递归(,您仍然需要提供声明:

#include <iostream>
namespace {
int DivThree(int val); // needed to implement AddOne()
int AddOne(int val) {
std::cout << "AddOne " << val << " -> " << (val + 1) << 'n';
if (val > 0) return DivThree(val + 1);
return val;
}
int DivThree(int val) {
std::cout << "DivThree " << val << " -> " << (val / 3) << 'n';
return AddOne(val / 3);
}
}
int main(){
int final = AddOne(18);
std::cout << "Final " << final << 'n';
return 0;
}

而且,是的,这是非常人为的,但是循环递归的好例子很少而且相距甚远:-(输出为:

AddOne 18 -> 19
DivThree 19 -> 6
AddOne 6 -> 7
DivThree 7 -> 2
AddOne 2 -> 3
DivThree 3 -> 1
AddOne 1 -> 2
DivThree 2 -> 0
AddOne 0 -> 1
Final 0

(a(CPP Core Guidline SF.22实际上涵盖了以下内容:

对所有内部/非导出实体使用未命名(匿名(命名空间。

原因:任何外部内容都不能依赖于嵌套的未命名命名空间中的实体。请考虑将实现源文件中的每个定义放在未命名的命名空间中,除非该定义定义"外部/导出"实体。

API 类及其成员不能位于未命名的命名空间中;但在实现源文件中定义的任何"帮助程序"类或函数都应位于未命名的命名空间范围内。

如果你只对函数进行操作,正如@paxdiablo所写的那样,你可以使用匿名命名空间(看看他的回答(。

我有一些基于C的习惯,所以我个人也会将其视为static功能。但我不确定C++狂热分子:)会如何看待它。static(在此上下文中(使编译单元(logging.cpp(的函数在本地,因此无法从外部链接。

//logging.cpp
static void Prettify(std::string& ugly);
void LogThis(const std::string& text) {
Prettify(text);
std::cout << "Log: " << text << 'n';
}
static void Prettify(std::string& ugly) { }

但是,如果您的日志记录实用程序是面向对象的。我建议你使用D指针和Q指针设计模式(也称为PImpl习语( - https://en.cppreference.com/w/cpp/language/pimpl 。

//logging.h
#include <string>
class loggingImpl;
class logging {
public :
logging();
virtual ~logging();
void LogThis(const std::string& text);
protected :
loggingImpl *impl;
};
//logging.cpp
class loggingImpl
{
public :
loggingImpl(logging *p) : qptr(p) { }
void Prettify(std::string& ugly) { }
//anything what you need and should be hided
// access parent through qptr
protected :
logging *qptr;
};
logging::logging() : impl(new loggingImpl) { }
logging::~logging() { delete impl; }
void logging::LogThis(const std::string& text) {
impl->Prettify(text);
std::cout << "Log: " << text << 'n';
}

正如您所写的,由于限制了未使用符号的可见性,将声明放在头文件中是不正确的。