gpt4 book ai didi

c++ - 如何在 C++ 共享库中隐藏业务对象的实现细节并提供接口(interface)

转载 作者:太空狗 更新时间:2023-10-29 21:44:12 24 4
gpt4 key购买 nike

我想要一个共享库并将这个库传递给一些 Qt 插件。 Qt 插件与库/库的界面一起工作(创建一些东西,编辑它们等)。 我的计划:

  • 启动Qt应用程序和共享库(共享库在编译时链接,所以不需要使用dlopen/LoadLibrary和解析,应用程序只需要找到库)
  • 搜索 Qt 插件并加载它们
  • 将共享库传递给 Qt 插件
  • 让 Qt 插件与库一起工作

整个 Qt 的东西很清楚,并且可以在 Linux、Unix 和 Windows(使用 GCC 和 MSVC)下工作。请注意以下几点:

  • 我有 Java 背景。在 Java 中会有一个接口(interface),一个实现接口(interface)的抽象类和一个扩展抽象类的业务类。也许是一个用于创建业务对象并将接口(interface)返回给库用户的工厂类。但是业务对象永远不能从类外部访问,因为它是包保护的
  • 根据信息 1:如何使用 C++ 实现同样的效果?我的想法如下(代码在最后):
    • Factory:创建业务对象,但返回接口(interface)
    • 接口(interface):与虚函数的接口(interface)
    • 业务类:实现接口(interface)
    • 导出工厂和接口(interface),隐藏业务类
  • 解决方案必须独立于平台
  • 在编译时链接库并避免 dlopen/LoadLibrary & resolve
  • 使业务对象只能通过接口(interface)或工厂访问

这导致了以下问题:

  1. 为什么 dataobjectabuseddataobject BOTH 可以访问?为什么不仅工厂创建的对象(接口(interface))(而且 abuseddataobject 确实会触发编译器错误)?这个想法是隐藏业务对象并使其只能通过接口(interface)访问并且只能由工厂创建。该库确实负责 GCC __attributes__ ?有什么错误/问题?
  2. 这是在 C++ 中执行此操作的常用方法,还是我“对 Java 视而不见”(请参阅​​ C++ 代码)并混淆了 Java 和 C++?
  3. 如果我不了解 Java,那么在 C++ 中执行此操作的(常见)方法是什么(请附上代码示例)?

主要.cpp

#include <iostream>
#include "library/Extern.h"
#include "library/Factory.h"
#include "library/DataInterface.h"
#include "library/Data.h" // NOTE: User abuses our interface and includes the data object

int main(void)
{
// Create the factory and get an interface object
Factory factory;
DataInterface *dataobject = factory.getDataObject();

// Play around
std::cout << "Value:" << dataobject->getValue() << std::endl;

// But now someone abuses our data object ... WHY IS THIS POSSIBLE ?
Data *abuseddateobject = new Data();
std::cout << "Abused value:" << abuseddateobject->getValue() << std::endl;

// Cleanup
delete dataobject;
delete abuseddateobject;

return 0;
}

工厂.h

#ifndef FACTORY_H
#define FACTORY_H

#include "Extern.h"
#include "DataInterface.h"
#include "Data.h"

class DLL_PUBLIC Factory
{
public:
DLL_PUBLIC DataInterface *getDataObject();
};
#endif // FACTORY_H

工厂.cpp

#include "Factory.h"

DataInterface *Factory::getDataObject()
{
return new Data();
}

数据接口(interface).h

#ifndef DATAINTERFACE_H
#define DATAINTERFACE_H

#include "Extern.h"

class DLL_PUBLIC DataInterface
{
public:
DLL_PUBLIC virtual ~DataInterface() {}
DLL_PUBLIC virtual int getValue() = 0;
};
#endif // DATAINTERFACE_H

数据.h

#ifndef DATA_H
#define DATA_H

#include "Extern.h"
#include "DataInterface.h"

class DLL_LOCAL Data : public DataInterface
{
public:
DLL_LOCAL int getValue()
{
return 42;
}
};

#endif // DATA_H

最后是 Extern.h。库构建系统 (CMake) 确实为共享库定义了 BUILDING_DLL,所以这不是问题所在。目前我只是在为 Linux 编写原型(prototype),因此 Windows 支持并不重要

外部.h

#ifndef SOMECLASSEXTERN_H
#define SOMECLASSEXTERN_H

// Taken from: http://gcc.gnu.org/wiki/Visibility

#if defined _WIN32 || defined __CYGWIN__
#ifdef BUILDING_DLL
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllexport))
#else
#define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
#endif
#else
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllimport))
#else
#define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
#endif
#endif
#define DLL_LOCAL
#else
#if __GNUC__ >= 4
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
#endif

#endif // SOMECLASSEXTERN_H

感谢您花时间回答这个问题

最佳答案

简而言之:#include "library/Data.h" 应该无法编译。

Data 类是库的一个实现细节。它永远不应该提供给用户!您应该将 interfaceimplementation 头文件分开,比如在单独的文件夹中,并设置构建,以便库的用户无法访问实现文件.仅仅因为它是一个头文件并不意味着它是接口(interface)的一部分!

吹毛求疵:我猜你同意你应该使用 C++,而不是一些可憎的 SCSS C/C++。因此:

  1. 我建议使用智能指针,例如QScopedPointerstd::unique_ptrdelete foo 的每个实例都应该被怀疑地看待,除非它是一个实现细节。编译器负责 RAII 的尾端- 使用它。

  2. 您的Factory 类是否应该是可实例化的是值得怀疑的。可能你应该让它成为一个只有静态成员的类,或者甚至是接口(interface)类中的静态成员。如果您有多个可以构建的类型,工厂函数可以将所需类型作为参数。

  3. (void) 参数声明仅属于 C,在 C++ 中绝对没有位置。这是因为在 C 中,以下与 void foo(void) 等价但不同:

    void foo();
    void foo(...);

    在 C++ 中不是这种情况!

您的 main 可能如下所示:

int main()
{
QTextStream out(stdout);
QScopedPointer<DataInterface> data1 = DataInterface::create("Data");

out << "Value:" << data1->value() << endl;

return 0;
}

关于c++ - 如何在 C++ 共享库中隐藏业务对象的实现细节并提供接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20751508/

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