首页 文章

在C中转发嵌套类型/类的声明

提问于
浏览 1346
174

我最近遇到了这样的情况:

class A
{
public:
    typedef struct/class {...} B;
...
    C::D *someField;
}

class C
{
public:
    typedef struct/class {...} D;
...
    A::B *someField;
}

通常你可以声明一个类名:

class A;

但是你不能转发声明一个嵌套类型,以下导致编译错误 .

class C::D;

有任何想法吗?

6 回答

  • 197

    这将是一种解决方法(至少对于问题中描述的问题 - 不是针对实际问题,即,当无法控制 C 的定义时):

    class C_base {
    public:
        class D { }; // definition of C::D
        // can also just be forward declared, if it needs members of A or A::B
    };
    class A {
    public:
        class B { };
        C_base::D *someField; // need to call it C_base::D here
    };
    class C : public C_base { // inherits C_base::D
    public:
        // Danger: Do not redeclare class D here!!
        // Depending on your compiler flags, you may not even get a warning
        // class D { };
        A::B *someField;
    };
    
    int main() {
        A a;
        C::D * test = a.someField; // here it can be called C::D
    }
    
  • 29

    你不能这样做,这是C语言的一个漏洞 . 您必须取消嵌套至少一个嵌套类 .

  • 3
    class IDontControl
    {
        class Nested
        {
            Nested(int i);
        };
    };
    

    我需要一个前向引用,如:

    class IDontControl::Nested; // But this doesn't work.
    

    我的解决方法是:

    class IDontControl_Nested; // Forward reference to distinct name.
    

    后来我可以使用完整的定义:

    #include <idontcontrol.h>
    
    // I defined the forward ref like this:
    class IDontControl_Nested : public IDontControl::Nested
    {
        // Needed to make a forwarding constructor here
        IDontControl_Nested(int i) : Nested(i) { }
    };
    

    如果有复杂的构造函数或其他特殊的成员函数没有顺利继承,那么这种技术可能比它的 Value 更麻烦 . 我可以想象某些模板魔法反应很糟糕 .

    但在我非常简单的情况下,它似乎工作 .

  • 1

    我不会称之为答案,但仍然是一个有趣的发现:如果你在名为C的命名空间中重复结构的声明,一切都很好(至少在gcc中) . 当找到C的类定义时,它似乎无声地覆盖了namspace C.

    namespace C {
        typedef struct {} D;
    }
    
    class A
    {
    public:
     typedef struct/class {...} B;
    ...
    C::D *someField;
    }
    
    class C
    {
    public:
       typedef struct/class {...} D;
    ...
       A::B *someField;
    }
    
  • 0

    如果你真的想避免#include头文件中令人讨厌的头文件,你可以这样做:

    hpp file:

    class MyClass
    {
    public:
        template<typename ThrowAway>
        void doesStuff();
    };
    

    cpp file

    #include "MyClass.hpp"
    #include "Annoying-3rd-party.hpp"
    
    template<> void MyClass::doesStuff<This::Is::An::Embedded::Type>()
    {
        // ...
    }
    

    但是之后:

    • 您必须在调用时指定嵌入类型(特别是如果您的函数不采用嵌入类型的任何参数)

    • 你的功能不能是虚拟的(因为它是一个模板)

    所以,是的,权衡......

  • 0

    这可以通过 forward declare the outer class as a namespace 来完成 .

    示例:我们必须使用嵌套类others :: A :: Nested in others_a.h,这是我们无法控制的 .

    others_a.h

    namespace others {
    struct A {
        struct Nested {
            Nested(int i) :i(i) {}
            int i{};
            void print() const { std::cout << i << std::endl; }
        };
    };
    }
    

    my_class.h

    #ifndef MY_CLASS_CPP
    // A is actually a class
    namespace others { namespace A { class Nested; } }
    #endif
    
    class MyClass {
    public:
        MyClass(int i);
        ~MyClass();
        void print() const;
    private:
        std::unique_ptr<others::A::Nested> _aNested;
    };
    

    my_class.cpp

    #include "others_a.h"
    #define MY_CLASS_CPP // Must before include my_class.h
    #include "my_class.h"
    
    MyClass::MyClass(int i) :
        _aNested(std::make_unique<others::A::Nested>(i)) {}
    MyClass::~MyClass() {}
    void MyClass::print() const {
        _aNested->print();
    }
    

相关问题