Advanced declarations / includes template classes - "invalid use of incomplete type"

Hey guys. Thanks for the click. I struggle with the included. Basically, I am trying to create a template class where there is a function that takes a specific instance of this template. To illustrate this, I made the following contrived example.

Say I have a world of people marked with a template (generic) data type. I have a specific person called king. And all people should be able to kneel before the king. Individuals, in general, can be marked as anything. Kings are indicated by numbers (1st, 2nd king).

Error

g++ -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H -c -o Individual.o Individual.cpp g++ -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H -c -o King.o King.cpp In file included from King.h:3, from King.cpp:2: Individual.h: In member function 'void Individual<Data>::KneelBeforeTheKing(King*)': Individual.h:21: error: invalid use of incomplete type 'struct King' Individual.h:2: error: forward declaration of 'struct King' make: *** [King.o] Error 1 

Individual.h (Individual.cpp is empty)

 //Individual.h #pragma once class King; #include "King.h" #include <cstdlib> #include <cstdio> template <typename Data> class Individual { protected: Data d; public: void Breathe() { printf("Breathing...\n"); }; void KneelBeforeTheKing(King* king) { king->CommandToKneel(); printf("Kneeling...\n"); }; Individual(Data a_d):d(a_d){}; }; 

King.h

 //King.h #pragma once #include "Individual.h" #include <cstdlib> #include <cstdio> class King : public Individual<int> { protected: void CommandToKneel(); public: King(int a_d): Individual<int>(a_d) { printf("I am the No. %d King\n", d); }; }; 

King.cpp

 //King.cpp #include "King.h" #include <string> int main(int argc, char** argv) { Individual<std::string> person("Townsperson"); King* king = new King(1); king->Breathe(); person.Breathe(); person.KneelBeforeTheKing(king); } void King::CommandToKneel() { printf("Kneel before me!\n"); } 

Makefile

 CXX = g++ CXXFLAGS = -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H OBJS = Individual.o King.o test: $(OBJS) $(CXX) -o $@ $^ clean: rm -rf $(OBJS) test all: test 
+4
source share
5 answers

Your two King and Individual classes are very closely related.

The presence of two such headers will not work, because they both need each other.

If your classes should be designed this way, then:

  • Define the Individual class first, but don't implement KneelBeforeTheKing, just declare this function.

  • Then define King

  • Then follow the method described above.

However, your design is probably wrong. For example, your template class has many methods that are independent of the tamplated type, including KneelBeforeTheKing, and should be reorganized from the template.

+3
source
 error: invalid use of incomplete type 'struct King' 

This means that you only declared King without its definition. You have problems with circular inclusions ( Individual.h and King.h include each other). This article should shed light on this issue.

+3
source

Well, the problem here is not related to templates.

You call the specialized functionality of the child in the base class. This is almost always a bad design sign.

What about inverting classes? Something like this (may contain errors):

 template < typename PersonType > class Person : PersonType { public: void command_to_kneel() { PersonType::command_to_kneel(); } void kneel_before_king(Person<King>* king) { king->command_to_kneel(); } void breathe() { } }; int main() { Person<King> king; Person<Knight> knight; knight.kneel_before_king(&king); } 
+2
source

You can break the dependency by adding another base class (e.g. NobleBase) to the King class:

 struct NobleBase { virtual void KneelBefore() = 0; }; class King : public Individual<int>, public NobleBase 

and change the void KneelBeforeTheKing(King* king) method
to that
void KneelBeforeTheKing(NobleBase* king)

Then you need to include the title for the NobleBase class.

+1
source

The syntax and errors of the compiler aside, I think the biggest problem is that your individual tells the King to tell himself to kneel.

 void KneelBeforeTheKing(King* king) { king->CommandToKneel(); printf("Kneeling...\n"); }; 

As Let_Me_Be noted, this is a design issue, not a syntax. In fact, the king must decide when people will kneel, so it makes sense that any calls to CommandToKneel () come from the king himself, and a set of individuals should be given as an argument to indicate who is being ordered.

The syntax problem is that you are trying to use functionality that has not been defined. The entire subsequent declaration for the king says that the header file for Individual is of type King. At this point, the compiler does not know anything about the members of the king, because you did not include a header file declaring these members, and you did not define King anywhere before using it.

However, as already indicated, the presence of any reference to a derived type (i.e., king) in the declaration of its base type (i.e., individual) is a poor design. A base class should not know anything about its derived types.

0
source

All Articles