Forward declaration of nested types/classes in C++

前端 未结 7 1101
刺人心
刺人心 2020-11-22 10:45

I recently got stuck in a situation like this:

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

class C
{
public:
    typedef          


        
相关标签:
7条回答
  • 2020-11-22 11:01

    If you really want to avoid #including the nasty header file in your header file, you could do this:

    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>()
    {
        // ...
    }
    

    But then:

    1. you will have to specify the embedded type at call time (especially if your function does not take any parameters of the embedded type)
    2. your function can not be virtual (because it is a template)

    So, yeah, tradeoffs...

    0 讨论(0)
  • 2020-11-22 11:04

    I would not call this an answer, but nonetheless an interesting find: If you repeat the declaration of your struct in a namespace called C, everything is fine (in gcc at least). When the class definition of C is found, it seems to silently overwrite the 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 讨论(0)
  • 2020-11-22 11:08

    You can't do it, it's a hole in the C++ language. You'll have to un-nest at least one of the nested classes.

    0 讨论(0)
  • 2020-11-22 11:10

    This can be done by forward declare the outer class as a namespace.

    Sample: We have to use a nested class others::A::Nested in others_a.h, which is out of our control.

    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();
    }
    
    0 讨论(0)
  • 2020-11-22 11:19

    This would be a workaround (at least for the problem described in the question -- not for the actual problem, i.e., when not having control over the definition of 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
    }
    
    0 讨论(0)
  • 2020-11-22 11:21

    If you have access to change the source code of classes C and D, then you can take out class D separately, and enter a synonym for it in class C:

    class CD {
    
    };
    
    class C {
    public:
    
        using D = CD;
    
    };
    
    class CD;
    
    0 讨论(0)
提交回复
热议问题