gpt4 book ai didi

c++ - C/C++ API设计困境

转载 作者:行者123 更新时间:2023-11-30 03:44:10 24 4
gpt4 key购买 nike

我一直在分析 C++ 中的 API 设计问题,以及在将接口(interface)与实现分离时如何解决语言中的一个大漏洞。

我是一个纯粹主义者,坚信将系统的公共(public)接口(interface)与有关其实现的任何信息巧妙地分开。我每天都在一个巨大的代码库上工作,它不仅构建起来真的很慢,主要是因为头文件拉动了大量其他头文件,而且作为客户端也非常难以挖掘某些东西的作用,因为接口(interface)包含各种供公共(public)、内部和私有(private)使用的功能。

我的图书馆分为几层,每一层都使用其他层。向客户公开每个级别是一种设计选择,这样他们就可以通过使用较低级别的实体来扩展高级实体的功能,而无需 fork 我的存储库。

现在问题来了。在考虑了很长时间如何做到这一点之后,我得出的结论是,在 C++ 中几乎没有办法以满足所有 满足以下要求:

  1. 它不需要任何代码重复/冗余。原因:它不可扩展,虽然它对一些类型没问题,但它很快就会变成很多实际代码库的代码。代码库中的每一行都有维护成本,我更愿意花在有意义的代码行上。

  2. 零开销。原因:我不想为在编译时(或至少应该!)众所周知的东西支付任何性能。

  3. 这不是黑客攻击。原因:可读性、可维护性,而且因为它太丑了。

据我所知,这也是我的问题所在,在 C++ 中,有三种方法完全从类的公共(public)接口(interface)中隐藏类的实现。

  1. 虚拟接口(interface):违反要求 1(代码重复)和 2(开销)。
  2. Pimpl:违反了要求 1 和 2。
  3. 重新解释将 this 指针强制转换为 .cpp 中的实际类。零开销,但引入了一些代码重复并违反了 (3)。

C 在这里获胜。为您的实体定义一个不透明的句柄和一堆将该句柄作为第一个参数的函数很好地满足了所有要求,但这不是惯用的 C++。我知道有人可能会说“在编写 C++ 时只使用 C 风格”,但它没有回答这个问题,因为我们正在谈论一个惯用 C++ 解决方案。

最佳答案

Defining an opaque handle to your entity and a bunch of function that take that handle as the first argument beautifully satisfies all requirements, but it is not idiomatic C++.

您仍然可以将它封装在一个类中。不透明句柄将是该类的唯一私有(private)数据成员,它的实现不会以任何方式公开。在实现方面,它只是一个指向私有(private)数据结构的指针,由类的成员函数取消引用。这仍然是对 C 解决方案的一个小改进,因为所有相关数据和函数都将封装在一个类中,这使得客户端无需跟踪句柄并将其传递给每个函数。

是的,我想取消对指针的引用会引入一些微不足道的开销,但 C 解决方案也会有同样的问题。

不需要重复代码,虽然可以说它被认为是 hack(或者至少是不优雅的 C++ 设计),但它肯定不会比用 C 实现的相同方法更 hack。唯一的区别是 C 程序员对什么是“hack”的阈值较低,因为他们的语言表达设计的方式较少。

我正在考虑的设计草图(与 PIMPL 基本相同,但只有数据成员不透明):

// In a header file:

class DrawingPen
{
public:

DrawingPen(...); // ctor
~DrawingPen(); // dtor

void SetThickness(int thickness);
// ...and other member functions

private:
void *pPen; // opaque handle to private data
};
// In an implementation file:

namespace {
struct DrawingPenData
{
int thickness;
int red;
int green;
int blue;
// ... whatever else you need to describe the object or track its state
};
}


// Definitions of the ctor, dtor, member functions, etc.
// For instance:

void DrawingPen::SetThickness(int thickness)
{
// Get the object data through the handle.
DrawingPenData *pData = reinterpret_cast<DrawingPenData*>(this->pPen);

// Update the thickness.
pData->thickness = thickness;
}

如果您需要在 DrawingPen 上工作的私有(private)函数,但您不想在 DrawingPen header 中公开,您只需将它们放在同一个匿名中实现文件中的命名空间,接受对类对象的引用。

关于c++ - C/C++ API设计困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35669729/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com