共享库中的 D 指针和组合 类
D-pointer and composition classes in a shared library
我正在用 Qt5 C++ 创建一个共享库。为了允许未来的更新保留二进制兼容性,我想使用 d 指针技术。但是,当有classes的组合时,我不知道如何应用它。我找到的例子,包括 here,只解释了 class 继承的情况。我的问题是
Do I need to make a corresponding private class for each class in the
library (myLib, B and C) or only for the main one (myLib) and how to access them later?
这是我的设置和没有私有 classes 的所需功能:
myLib.h
#include "B.h"
class myLib;
{
public:
myLib();
B *getB(int n);
private:
QList<B *> m_b;
}
B.h
#include "C.h"
class B;
{
public:
B();
C *getC(int n);
private:
QList<C *> m_c;
}
C.h
class C;
{
public:
C();
int getVar();
private:
int m_var;
}
在主应用的某处:
myLib *m_lib = new myLib();
int k = m_lib->getB(4)->getC(2)->getVar();
来自链接:问题 "Never change the size of an exported C++ class"。
解决方案:"The trick is to keep the size of all public classes of a library constant by only storing a single pointer. This pointer points to a private/internal data structure that contains all the data."。
只要你的 class 不显示给你的库的使用者,就可以随意 D-pointerless。 "shown to the consumers" 我的意思是 "with their full definition made available by declarations in the headers meant to be included by the consumer code"。可能 public/private 一词在这里受到了 'semantic overload' 的影响,让我们使用 'exposed'/'opaque'(参见 ** 脚注)
在您的示例中,B
和 C
都公开了,因此它们必须可用 "by pointers only"。
myLib
class也是如此。更糟糕的是:myLib
的实例可以通过值获取,因为构造函数是 public
。这意味着我可以做类似的事情:
myLib libObj;
libObj.getB(4)->getC(2)->getVar();
这将使 myLib
的未来版本无法获得 "drop in replacements, no recompilation needed"。
我建议强制消费者通过工厂方法获取 myLib
(或 'singleton')的实例。在线内容:
class myLib {
private:
myLib() {
}
public:
static myLib* createInstance() {
return new myLib();
}
};
** 例如 "exposed/opaque declaration" - class B
暴露给图书馆消费者(他们知道 B
-s 会有..咳咳...私人部分),但大约 class M
消费者只知道它存在并且图书馆将提供指向它的指针:
文件"myLib.hpp"
// M_type is a pointer to a class and that's all you,
// the consumer, need to know about it. You give me an M_type
// and ask specific questions about it and you'll
// get the details or access to data I choose to
// make available to you
typedef class M * M_type;
// Dear the library consumer, this class is public to you.
// You know I'm keeping a list of M_type, even if you also know
// you'll never get you hands directly on that list, because
// it has a private access. But having this information,
// **you can compute the sizeof(B)**.
class B {
public:
B();
M_type getM(int n);
const M_type getM(int n) const;
// that is one of the "questions" you can ask about an M_type
const char* getMLabel(const M_type var) const;
// I'm providing you with access to something that allows
// you to modify the amount stored by an M_type,
// even if you don't know (and never will) how
// I'm storing that amount
int& getMAmount(M_type var);
// You don't need to know how to create M-s, I'll
// be doing it for you and provide the index of the created
// M_type. Ask me with getM to get that pointer.
inr registerM(const char* label, int amount);
private:
QList<M_type> ems;
};
某处,在库代码的深处,将存在一个 header 来定义 class M
是什么,myLib.cpp
将包含它,但是 header 将仅用于编译库,从不随 myLib binary 版本提供。
因此,class M
对于图书馆消费者来说是不透明的(相对于公开的)。
我正在用 Qt5 C++ 创建一个共享库。为了允许未来的更新保留二进制兼容性,我想使用 d 指针技术。但是,当有classes的组合时,我不知道如何应用它。我找到的例子,包括 here,只解释了 class 继承的情况。我的问题是
Do I need to make a corresponding private class for each class in the library (myLib, B and C) or only for the main one (myLib) and how to access them later?
这是我的设置和没有私有 classes 的所需功能:
myLib.h
#include "B.h"
class myLib;
{
public:
myLib();
B *getB(int n);
private:
QList<B *> m_b;
}
B.h
#include "C.h"
class B;
{
public:
B();
C *getC(int n);
private:
QList<C *> m_c;
}
C.h
class C;
{
public:
C();
int getVar();
private:
int m_var;
}
在主应用的某处:
myLib *m_lib = new myLib();
int k = m_lib->getB(4)->getC(2)->getVar();
来自链接:问题 "Never change the size of an exported C++ class"。
解决方案:"The trick is to keep the size of all public classes of a library constant by only storing a single pointer. This pointer points to a private/internal data structure that contains all the data."。
只要你的 class 不显示给你的库的使用者,就可以随意 D-pointerless。 "shown to the consumers" 我的意思是 "with their full definition made available by declarations in the headers meant to be included by the consumer code"。可能 public/private 一词在这里受到了 'semantic overload' 的影响,让我们使用 'exposed'/'opaque'(参见 ** 脚注)
在您的示例中,B
和 C
都公开了,因此它们必须可用 "by pointers only"。
myLib
class也是如此。更糟糕的是:myLib
的实例可以通过值获取,因为构造函数是 public
。这意味着我可以做类似的事情:
myLib libObj;
libObj.getB(4)->getC(2)->getVar();
这将使 myLib
的未来版本无法获得 "drop in replacements, no recompilation needed"。
我建议强制消费者通过工厂方法获取 myLib
(或 'singleton')的实例。在线内容:
class myLib {
private:
myLib() {
}
public:
static myLib* createInstance() {
return new myLib();
}
};
** 例如 "exposed/opaque declaration" - class B
暴露给图书馆消费者(他们知道 B
-s 会有..咳咳...私人部分),但大约 class M
消费者只知道它存在并且图书馆将提供指向它的指针:
文件"myLib.hpp"
// M_type is a pointer to a class and that's all you,
// the consumer, need to know about it. You give me an M_type
// and ask specific questions about it and you'll
// get the details or access to data I choose to
// make available to you
typedef class M * M_type;
// Dear the library consumer, this class is public to you.
// You know I'm keeping a list of M_type, even if you also know
// you'll never get you hands directly on that list, because
// it has a private access. But having this information,
// **you can compute the sizeof(B)**.
class B {
public:
B();
M_type getM(int n);
const M_type getM(int n) const;
// that is one of the "questions" you can ask about an M_type
const char* getMLabel(const M_type var) const;
// I'm providing you with access to something that allows
// you to modify the amount stored by an M_type,
// even if you don't know (and never will) how
// I'm storing that amount
int& getMAmount(M_type var);
// You don't need to know how to create M-s, I'll
// be doing it for you and provide the index of the created
// M_type. Ask me with getM to get that pointer.
inr registerM(const char* label, int amount);
private:
QList<M_type> ems;
};
某处,在库代码的深处,将存在一个 header 来定义 class M
是什么,myLib.cpp
将包含它,但是 header 将仅用于编译库,从不随 myLib binary 版本提供。
因此,class M
对于图书馆消费者来说是不透明的(相对于公开的)。