使用前向类声明声明类对象(基本C ++)

时间:2018-06-08 08:07:17

标签: c++

我已经做了一些C ++已经有一段时间了,我有点生疏了。有人可以告诉我,如果这样的话可能会在向前声明一个类时声明一个类对象吗?

e.g。

/child::*[1]/child::*[1]

我特别要求,所以我可以像这样对象声明:

class MyClass MyObject;

/* ... */

class MyClass
{
public:
    void MyVariable;
} MyObject;

与低iq方式相反,采取2行:

// Header.hpp
class MyClass extern MyObject;


// Source.cpp
class MyClass
{
public:
    void MyVariable;
} MyObject;

2 个答案:

答案 0 :(得分:0)

您可以将extern放在类型前面(因为extern是一个存储类,而class MyClass是类型):

extern class MyClass myObject;

以上直接回答了有关语法的原始问题。然而,由于显然有一些混乱,我认为值得花掉我的答案。

首先,标准(n3690)的相关摘录:

§3.1.2:

  

宣言是一个   定义   除非它声明一个函数而没有指定函数的主体(8.4),它   包含   EXTERN   说明符(7.1.1)或a   联动规范   25   (7.5)并且都不是   初始化   也不是   功能-   身体   ,它在类定义(9.2,9.4)中声明了一个静态数据成员,它是一个类名声明(9.1),它是   一个   不透明枚举声明   (7.2),它是一个   模板参数   (14.1),它是一个   参数声明   (8.3.5)a   函数声明器不是   声明符   一个   函数的定义   ,或者它是一个   的typedef   声明(7.1.3),   一个   别名声明   (7.1.3),a   使用声明   (7.3.3),a   static_assert声明   (第7条),a   属性-   宣言   (第7条),a   空声明   (第7条),或a   使用指示符   (7.3.4)。

§3.2.5:

  

[注:   声明和表达式的规则描述了哪些上下文完成了类   类型是必需的。类类型   Ť   必须完整如果:

     

- 类型的对象   Ť   定义为(3.1),或

     

- 类型的非静态类数据成员   Ť   声明(9.2)或

     

- T.   用作a中的对象类型或数组元素类型   新的表达   (5.3.4),或

     

- 左值到左值的转换应用于引用类型对象的glvalue   Ť   (4.1),或

     

- 将表达式(隐式或显式)转换为类型   Ť   (第4,5.2.3,5.2.7,5.2.9,5.4条),   或

     

- 一个不是空指针常量的表达式,其类型不是   简历   无效*   ,转换为   类型指针   Ť   或参考   Ť   使用标准转换(第4条),a   的dynamic_cast   (5.2.7)   或者a   的static_cast   (5.2.9),或

     

- 类成员访问运算符应用于类型的表达式   Ť   (5.2.5),或

     

-   typeid的   运营商(5.2.8)或   的sizeof   operator(5.3.3)应用于类型的操作数   Ť   ,或

     

- 具有返回类型或参数类型类型的函数   Ť   定义为(3.1)或称为(5.2.2),或

     

- 具有类型基类的类   Ť   已定义(第10条)或

     

- 类型的左值   Ť   分配给(5.17)或

     

- 类型   Ť   是一个主题   alignof   表达式(5.3.6)或

     

- 一个   异常声明   有类型   Ť   ,参考   Ť   或指向   Ť   (15.3)。

     

- 结束说明]

现在,考虑问题中的第一个例子:

class MyClass MyObject;

/* ... */

class MyClass {} MyObject;

这是无效的,因为第一行是声明和定义,根据§3.1.2)。

第三个例子是有效的:

// Header.hpp
class MyClass;
extern MyClass MyObject;

// Source.cpp
class MyClass {} MyObject;

这是有效的,因为Header.hpp中的第二行只是一个声明(第3.1.2节),此时MyClass不一定是完整的类型(第一个要点)在第3.2.5节中。

答案中第二个例子的问题只是语法不正确。正如我上面所写,正确的方法是:

// Header.hpp
extern class MyClass myObject;

// Source.cpp
class MyClass {} myObject;
@Samer Tufail和@Frax建议这没用。也许它不是很有用,但我可以考虑以下用例:

  1. 转发声明类型以减少包含的标头数量。该类可以在另一个头中定义,仅当客户端代码需要访问全局对象的成员时才包含该类。

  2. 能够定义固定数量的全局对象,同时隐藏类定义(在源文件中)。可以使用自由函数来操纵这些对象。

  3. 在C API中包装全局对象(类类型):

  4. 3。的例子:

    // header.hpp
    struct MyClass
    {
        explicit MyClass(std::string s);
    
        const char* getString() const { return m_str.c_str(); }
    
    private:
        std::string m_str;
    };
    
    extern "C"
    {
        MyClass myObject("some string");
    
        const char* getString(const MyClass* obj) { return obj->getString(); }
    }
    
    // header.h (C API)
    extern struct MyClass myObject;
    
    const char* getString(const MyClass* obj);
    

    还有其他方法可以做这些事情,但使用前向声明的类型是可能的。恕我直言@Cryptoman询问很少使用,但有趣的功能,并没有理由低估这个问题。

答案 1 :(得分:-1)

您只能拥有指向前向声明的类的指针或引用,否则它是不完整的类型。

class MyClass;

class MyOtherClass
{
   public:
   // MyClass* obj;  pointer
   // MyClass& obj - reference
};

为什么会如此?想象您现在MyClass obj中有MyOtherClass。当调用MyOtherClass的ctor时,它必须构造MyClass,这不可能发生,因为它没有实现和/或类型不完整。