函数声明放在哪里?

问题描述 投票:0回答:1

比方说我要开发一个日志功能。在 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++ function coding-style encapsulation
1个回答
4
投票

对于那些 只是 文件中需要,我只需要把它放在C++文件本身的匿名命名空间中,有点像现代的传统C++文件中的 static 功能关键字(a):

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核心指导线SF.22实际上涵盖了这一点。

对所有内部不导出的实体使用未命名(匿名)的命名空间。

理由是 任何外部实体都不能依赖于嵌套的未命名命名空间中的实体。考虑将实现源文件中的每个定义都放在未命名的命名空间中,除非那是在定义一个 "externalexported "实体。

一个API类和它的成员不能住在一个未命名的命名空间中;但任何在实现源文件中定义的 "帮助者 "类或函数都应该在一个未命名的命名空间范围内。


0
投票

如果你只对函数进行操作,就像@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-poin。我建议你使用D-pointer和Q-pointer设计模式(也被称为PImpl习语)------。https:/en.cppreference.comwcpplanguagepimpl。 .

//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';
}

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

© www.soinside.com 2019 - 2024. All rights reserved.