c++中的部分类

partial class in C++

本文关键字:分类 c++      更新时间:2023-10-16

我希望避免重新编译包含公共头文件的所有内容,仅仅因为类定义的私有部分发生了某些更改。我正在研究PIMPL之外的其他选项。

这是我尝试过的:

我创建了一个包含类a的库:

A_p.h包含A类的私有部分

void PrivateMethod(int i);

A.h公共头文件:

class A
{
public:
    A();
    virtual ~A();
    // other public members
private:
#ifdef A_PRIVATE
#include "A_p.h"
#endif
};

A.cpp

#define A_PRIVATE
#include "A.h"
A::A() {}
A::~A() {}
void A::PrivateMethod(int i) { }

然后我创建了一个Win32控制台项目,其中包括公共头文件(A.h)和针对.lib文件的链接。

一切似乎都工作,但我想知道在此过程中是否有陷阱。有人能详细说明一下吗?

"Everything seems to work" - seems there is essential。你只是在经历未定义的行为。这是一个不规范的程序——一个类的定义在使用该类的编译单元之间必须是相同的。

由于这是UB,它似乎可以工作,但是尝试在私有部分声明virtual方法,您很可能会遇到一些可见的问题。

抽象类允许你通过子类化抽象类来声明一个公共接口但拥有私有数据和函数。

这不能按照你描述的方式工作,因此在c++标准中不支持的一个关键原因是,你提议的公共声明使得不可能知道A的大小。公共声明不显示私有数据需要多少空间。因此,只看到公共声明的代码不能执行new A,不能为A数组的定义分配空间,也不能对指向A的指针进行算术运算。

还有其他问题,可以通过某种方式解决,例如指向虚函数成员的指针的位置。但是,这会导致不必要的并发症。

要创建一个抽象类,必须在该类中声明至少一个虚函数。虚函数是用= 0定义的,而不是函数体。这表示它没有实现,因此抽象类的对象只能作为从它派生的类的子对象。

然后,在单独的私有代码中,声明并定义一个从A派生的类B。您将需要提供创建和销毁对象的方法,可能使用一个公共的"new"函数,该函数返回一个指向A的指针,并通过调用一个可以看到B声明的私有函数来工作,以及一个公共的"delete"函数,该函数接受一个指向A的指针,并通过调用一个可以看到B声明的私有函数来工作。

有三种方法可以隐藏这类信息:

  1. 向前声明您的类。只有当它只是通过客户端代码传递(通过指针和/或引用),并且只有在库中使用时才有效。您的库首先需要提供工厂函数或类似的返回指针/引用,客户端永远不能调用newdelete

  2. 暴露抽象基类,并再次提供工厂函数(实例化仅在库中可见的具体派生类)

  3. 使用
  4. pimpl

我也同意你应该重新考虑那些大到需要隐藏它的类,但是如果你真的不能把它分开,这些都是你的选择。


至于如何&为什么在实践中违反了ODR:

  • 库和它的客户端代码可以对实例的大小有不同的意见。这可能导致分配/回收等问题。
  • 他们也可以期望不同的数据成员偏移量,虚值表布局等。
    • p。出于这些目的,内联方法算作客户端代码,因为它们不会通过添加新的动态库构建来更新
    • pp。较新的优化器可能能够在不知道
    • 的情况下内联一些行外方法。

如前所述,在c++中不可能有适当的特定类,在某些情况下这实际上很烦人。继承和Pimpl模式提供了另一种选择,但是每个对象都有一个指针的开销,这在内存有限的嵌入式软件中可能会很高。

为了解决这个问题,有一个官方的"局部类"。给ISO的建议:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0309r0.pdf

不幸的是,提案被拒绝了。