当前位置: 首页 > 知识库问答 >
问题:

命名空间中类的前向声明

谈灵均
2023-03-14

如何在命名空间中转发声明类。例如,下面是一个库的头文件,用户不需要知道私有的myPtr,所以当包含在头文件下面时,不需要包含boost头文件。那么我如何向前声明boost::shared_ptr以启用用户代码编译呢?

MyClass.h

class MyClass
{

private:

  boost::shared_ptr<Mytype> myPtr;

}

共有1个答案

公孙宗清
2023-03-14

这里需要包含 。没有(聪明的)办法绕过它。但是mytype本身可以向前声明。

当然,您可以在头的顶部编写#include ,这样您的用户就不必自己完成了。提供自治头(即可以在没有错误的情况下首先包含的头)实际上是一个很好的实践。

关于正向编译的规则略显复杂。理解他们的原因比尝试和记住所有的案例要容易得多。

有两个因素:

  • 语义
  • 内存属性(大小和对齐)

语义:为了访问对象的方法、属性或基类,您需要了解它们。当然,除了构造函数、赋值运算符和析构函数(即使是自动生成的)都是方法之外,这似乎是显而易见的。很容易忘记他们。

内存属性:与大多数语言不同,C++试图尽可能地高效,这意味着它将为对象分配内存,而不是将其分配到某个地方,并且只在使用点使用指针,当然除非您指示它这样做(通过使用指针或引用)。为了知道要分配多少,编译器需要查看对象的内脏(即引擎盖下面是什么)。这意味着,即使不能访问确切的细节(private/protected东西),它们也需要是可见的,这样就可以看到需要在8字节边界上对齐的24个字节(顺便说一下,与shared_ptr无关)。

在标准中,我们说对象的定义对于这两种需求(方法和内存布局)中的任何一种都是必需的。如果定义是必需的,那么它显然必须是可用的。

好了,现在我们知道了原因,我们可以检查各种东西了。在下列情况下是否需要定义:

  • 是否使用对象作为sizeofalignof的参数?是(显然,需要内存属性)
  • 使用对象作为属性?是(需要内存属性)
  • 使用对象作为静态属性?no(1)
  • 使用指向对象的指针或引用作为属性?no(2)
  • 在函数声明中使用对象作为参数?no(3)
  • 在函数声明中使用对象作为返回类型?no(3)
  • 向周围的对象传递指针或引用?no(4)
  • 是否正在转换为基类?是(对基类的存在性和可访问性进行语义检查)
  • 是否转换为其他类型?依赖(5)

(1)声明不需要任何东西,但是静态属性的定义需要对象的定义。

(2)指针的大小不是32位就是64位(取决于你编译的方式,...)与对象无关。引用具有实现定义的表示形式。

(3)即使按值取/还!函数定义(如果在内部使用)或函数调用站点可能需要它。

(4)当然,如果您尝试使用它(p->foo()p.foo()),那就另当别论了。

(5)如果需要使用对象的转换运算符,那么它显然是必需的;否则,如果使用另一个类型的构造函数,则应用与函数相同的规则(但另一个类型定义是必需的)。

我希望事情现在更清楚了。

 类似资料:
  • 我有困难建立一个有3个类的结构。我不确定包含/转发声明。 下面的代码一直在编译,直到我在inclino.h中添加名称空间和枚举。我从Inclinomeasure.h收到“Inclino尚未声明”。 倾斜度。h 倾斜度 倾角读数.h 结构正确吗?如何访问其他类中的枚举? 提前道谢。 编辑:我修复了名称空间的问题,把它放在一个新的文件,包括由3类。但我似乎误用了include/forward声明。

  • 这是一个非常基本的问题,但实际上我从来没有自己定义过名称空间。我正在尝试将我的基于Qt的库中的类分组在各种名称空间中(并且还允许更容易的扩展而不发生名称冲突)。例如,主类(也表示库)属于顶级命名空间: 这个使用了一组其他名称空间和类,这些名称空间和类是在的头文件中定义的,这些头文件包含在的头文件中: 其中Manager.h包含 和configurator.h包含 类的内容在这里并不重要。 在编译时

  • 所以我对Qt和C++都是新手,但我想弄清楚下面的代码是怎么回事。 我有一个头文件和源文件charinfowindow。在我拥有的源文件中: 在头文件中 我试着找出这些代码在网上做什么,但我只是在找关于如何做的资源。 如果有人能告诉我,首先,这些代码是做什么的,其次,他们为什么这样做。不胜感激。 谢谢

  • 我试图在头文件中使用前向声明来减少#includes used,从而减少用户包含我的头文件时的依赖关系。 但是,我无法在使用名称空间的地方转发decalre。参见下面的示例。 这里是我非常做作的工作代码使用下面的答案。

  • 在调用axis2 1.7.5(Wsdl2Java)生成的存根时,有人知道如何解决以下问题吗? 我发现存根发送了以下请求,但没有添加/定义SOAP版本(xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/)这是问题的根源 因此,我尝试如下设置SoapVersionURL 甚至可以直接将存根中的名称空间设置为 但是,这两种方法仍然忽略“xml

  • 我对C++不是很熟悉,这是我第一次使用的不仅仅是名称空间std。下面的有什么区别? VS 在这两个之后,我现在似乎可以创建一个MyClass对象了。一种方式比另一种好吗?另外,如果我都不这样做,我还可以通过每次需要时在MyNamespace::MyClass之前附加MyClass来引用MyClass吗? 接下来,如果我使用第二个选项转发declare,我还需要吗?在我(不是很好)的理解中,在C++