-1

Say I have 3 classes with following topology, and the actual code is somehow like this:

// formal system.h

#pragma once

namespace nianyi {
    class Proposition {
    public:
        class Term;
        class Expression;
        // Term::Value evaluate();
    };
    class Proposition::Term : public Proposition {
    public:
        class Variable;
        class Value;
    };
    class Proposition::Term::Value : public Proposition::Term {
    };
};

It's easy to see that if I uncomment that function declaration, the compiler is gonna complain about the un-previously-defined class Value, and indeed it does:

error C2027: use of undefined type 'nianyi::Proposition::Term'

But on the other hand, class Term is derived from its base class Proposition, which means I can't put its implementation in the base class since it's not a complete class before the implementation ends, and an incomplete class cannot be derived from.

Thus, putting the implementation of class Term both inside & outside class Proposition would lead to a compiler error. The inside one is caused by the incompleteness of the base class, and the outside one is caused by the incompleteness of the derivative.

So... what's the best way to solve this?


P.S. please stop telling "you should complete the definition before using a class" or "just don't make them nested". For the first kinda words, that's the whole problem there, simply telling this doesn't really help much; and for the second kinda words, I'm just intended to make them nested to not to expose those details.

Nianyi Wang
  • 712
  • 6
  • 13
  • Is this the actual code? The class definitions are missing semicolons. Show your actual code, and since you mentioned compiler errors, please show what they are. The errors are intended to be read. – paddy Jun 08 '18 at 03:08
  • @paddy Sorry for the misunderstanding. I was thinking that codes without redundant information would be easier to understand what I'm struggling with, so I've abstract the codes... Now they're updated to the actual codes. – Nianyi Wang Jun 08 '18 at 03:19
  • If this is the actual code, the problem is clear - the class Term is not defined... do "class Term{};" instead and you will get rid of the error. You probably should define term properly in another .h file though – aCuria Jun 08 '18 at 03:25
  • 1
    Yes, [mcve] is good, but **make sure it still demonstrates your problem**. – Yakk - Adam Nevraumont Jun 08 '18 at 03:25
  • Almost certainly your code is _not_ laid out the way you have indicated. This error means that whatever line of code is reporting it has seen the definition of `Proposition`, but not `Proposition::Term`. I'm willing to bet you have a circular dependency in how you're using your header files, or you just forgot to include one somewhere. – paddy Jun 08 '18 at 03:33
  • @aCuria I want to, but class `Term` is *inherited from class `Proposition`*, so it cannot be implemented in the base class, otherwise an "incomplete class" error would pop out - and in this case, even it is implemented outside the base class, it still need to be a complete class in order to be placed in the head of a function signature as a return type. Defining class `Term` in another header file doesn't actually help much... That's why I've posted this question, it's like a paradox, neither the both side of the coin (defining outside or inside the class) would give you the correct result. – Nianyi Wang Jun 08 '18 at 03:34
  • The code above does not make sense to me... Term is defined in Proposition and Term also inherits from Proposition? I don't think you can do this at all – aCuria Jun 08 '18 at 03:35
  • @aCuria Why tho? Nested classes are just nested grammatically, in most cases where it's defined doesn't really matter. (but in this case i does, it has to be implemented outside the base class, separated with its declaration) – Nianyi Wang Jun 08 '18 at 03:39
  • Topology doesn't have to be this complex. Example: Point, Line and Polygon are topological structure. A line is made of 2 points. A polygon is composed of lines. In this example, Point class has to be defined first. Line class is composed of Point class. Polygon class is composed of Line classes. I am not sure I am answering your question. From my knowledge of topology,the design shouldn't be this complex. – Nguai al Jun 08 '18 at 04:09
  • It appears to me that the unit base classes are Variable and Value. Second level classes are Term and Expressions. Top level class is Proposition. – Nguai al Jun 08 '18 at 04:12
  • And why exactly do you want to create this mess ? – Sid S Jun 08 '18 at 04:29
  • @SidS To not to expose those inner classes – Nianyi Wang Jun 08 '18 at 04:52
  • "I'm just intended to make them nested to not to expose those details." have you instead considered using opaque pointers (pImpl idiom) to hide the details? – AndersK Jun 11 '18 at 05:12

3 Answers3

0

This should work, not clear if its what you want though

class Proposition {
public:

};

class Term : public Proposition {
public:
    class Variable {};
    class Value {};
};

class Value : public Term {

};
aCuria
  • 6,935
  • 14
  • 53
  • 89
  • This is a pretty good solution, and I've thought in this way actually... But I was intended to make them nested. – Nianyi Wang Jun 08 '18 at 03:42
  • In this code `Term::Value` and `::Value` are different classes; the original code did not have such a thing – M.M Jun 08 '18 at 03:53
0

Here is an abstract solution. No need for inheritance.

class Variable{
};
class Value{
};
class Term{
   class Variable;
   class Value;
};
class Expression{
   class Variable;
   class Value;
};
class Proposition{
  class Expression;
  class Term;
};
Nguai al
  • 958
  • 5
  • 15
0

It seems like no one adresses the point in your question title that talks about returning a “doubly nested class inside its self”. I have seen this done a lot recently by making a private (or public if you like) member of the class and pointer instance of the class. This way you can generate and return a pointer to the class to this member.

// formal system.h

#pragma once

namespace nianyi {
    class Proposition {
    public:
        class Term;
        class Expression;
        // Term::Value evaluate();
    Proposition( )
    {
       Proposition *pinstance;
       prop_ = pinstance;
    }
private:
    Proposition *prop_;
    };
    class Proposition::Term : public Proposition {
    public:
        class Variable;
        class Value;
    };
    class Proposition::Term::Value : public Proposition::Term {
    };
};
NoGood
  • 33
  • 5