c++ - 在 OOP 中使用类 C API

标签 c++ api oop design-patterns singleton

我正在用 C++ 编写一些类作为个人小型库,但我遇到了一个问题。

我的一些对象让我们使用了以华丽的 C 风格编写的第三方库。 这意味着这些库具有像 apiInit()apiCleanup() 这样的函数,其中前者必须在任何实际的 api 函数之前调用,而后者必须在您调用时调用不会再使用它们了。

我想要的是为需要库的类提供对其函数的访问点,确保在创建第一个需要的类时调用 apiInit() ,或者至少在任何 api 函数之前调用被使用,并且当最后一个使用该 api 的实例被销毁时调用 apiCleanup()

请记住,不止一个类使用同一个库。

我可以提出两种解决方案:

首先,很明显,让提供者成为单例:

#include <iostream>

using namespace std;


class ContextProvider {

  ContextProvider() {
    cout << "Initializing API" << endl;
  }

  ContextProvider(ContextProvider const& rhs) = delete;
  ContextProvider& operator=(ContextProvider const& rhs) = delete;

public:

  ~ContextProvider() {
    cout << "Cleaning API" << endl;
  }

  static ContextProvider& getInstance() {
    static ContextProvider instance;
    return instance;
  }

  void useContext() {
    cout << "Using API" << endl;
  }
};


class ContextUser1 {


public:

  ContextUser1() {

  }

  void doSomething() {
    ContextProvider::getInstance().useContext();
  }
};


class ContextUser2 {

public:

  ContextUser2() {

  }

  void doSomethingElse() {
    ContextProvider::getInstance().useContext();
  }
};

另一个是保持上下文用户的计数器,像这样:

#include <iostream>

using namespace std;


class ContextProvider {
  static unsigned int userCounter;

public:

  ContextProvider() {
    if (userCounter == 0)
      cout << "Initializing API" << endl;

    ++userCounter;
  }

  ~ContextProvider() {
    --userCounter;

    if (userCounter == 0)
      cout << "Cleaning API" << endl;
  }

  void useContext() {
    cout << "Using API" << endl;
  }
};

unsigned int ContextProvider::userCounter = 0;


class ContextUser1 {
  ContextProvider cp;

public:

  ContextUser1() {
    cp = ContextProvider();
  }

  void doSomething() {
    cp.useContext();
  }
};


class ContextUser2 {
  ContextProvider cp;

public:

  ContextUser2() {
    cp = ContextProvider();
  }

  void doSomethingElse() {
    cp.useContext();
  }
};


int main() {
  ContextUser1 cu11, cu12, cu13;
  ContextUser2 cu21, cu22;

  cu11.doSomething();
  cu12.doSomething();
  cu21.doSomethingElse();
  cu22.doSomethingElse();
  cu13.doSomething();
}

两者,当使用以下 main()

执行时
int main() {
  ContextUser1 cu11, cu12, cu13;
  ContextUser2 cu21, cu22;

  cu11.doSomething();
  cu12.doSomething();
  cu21.doSomethingElse();
  cu22.doSomethingElse();
  cu13.doSomething();
}

输出预期结果,即:

Initializing API
Using API
Using API
Using API
Using API
Using API
Cleaning API

现在明显的问题是,哪个更好,或者我应该使用哪个?

例如,想到的一些事情是......

单例方法:

  • 优点:

    • 无需存储任何计数器。
    • 无需存储任何实例。
  • 缺点:

    • 语法变得奇怪(ContextProvider::getInstance().use())。
    • 它是一个单例,有它所有的缺陷。

反击方法:

  • 优点:

    • 用法很简单。
    • 语法清晰明了 (cp.use())。
  • 缺点:

    • 必须记录用户数量。
    • 用户类必须存储 ContextProvider 类的实例。

我问这个问题主要是因为我不知道这些优势/劣势中哪一个更重要,如果有我没有考虑到的东西,或者可能有明显的第三种方法我想不出来本质上比这两个更好,或者,谁知道呢。

感谢您的宝贵时间!

最佳答案

我会使用您的第二种方法,并进行以下修改:

class ContextUser1 {
  std::shared_ptr<ContextProvider> cp;

public:

  ContextUser1(const std::shared_ptr<ContextProvider>& cp)
      : cp(cp) {
  }

  void doSomething() {
      cp->useContext();
  }
};

使依赖关系显式使您的代码在可测试方面更好。此外,使用 shared_ptr 负责计数,因此您甚至不需要自己执行此操作。

关于c++ - 在 OOP 中使用类 C API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27889028/

相关文章:

c++ - 在 Windows 上使用 C++ 锁定文件

c++ - 如何打破双引号中的长行?

python - "Moving"在Python中从一个类到另一个类

javascript - Axios API Twitter 请求未返回用户推文

Delphi:存储从 TObjectList 获取的对象的正确方法

ruby - Ruby 中的单例模式与单态模式

c++ - 接受 std::array 的复制构造函数中的初始值设定项列表

c# - 在 C# 应用程序中运行 CPP 文件?

ios - Swift facebook 在 uitableview 中标记 friend

javascript - 用于站内搜索的谷歌算法