The intention of this code is to support multiple getters (sources of information) and multiple putters (destinations for that information). Before I can support multiple getters and putters, I need my code to compile properly with a single instance of each. What I am encountering is "expected class-name before { token" error messages that I don't know how to get around.
All of the code is attached. Here is an example of what is failing:
class Controller {...}
class GenericGetter : public Controller {... <- COMPILE ERROR
class GenericPutter: public Controller {... < COMPILE ERROR
class Getter : public GenericGetter { ... < COMPILE ERROR
class Putter: public GenericPutter { ... < COMPILE ERROR
Delta_G:
Post the code inline or attach as .txt or .ino. I'm not unzipping something from an unknown source. People using phones couldn't do that even if they wanted to.
I think these are the most relevant parts of his code:
You haven't included your Controller header for class GenericGetter : public Controller and the equivalent putter.
Overall your classes seem to be unusually well woven. Maybe take a pen and paper to draw out your class hierarchy/model and see if it makes sense on paper first.
Thanks, Karma. That was a good catch, but unfortunately that doesn't make any difference in the outcome.
Delta_G, I understand your concern. There are 11 files (5 headers and 5 cpp files & .ino). I tried posting them to my website, but WordPress won't upload the .cpp files.
I have been pounding on this problem for two weeks now. I have written and rewritten the code many times with no change in the outcome. Ultimately, my question boils down to this: How does a descendant class reference its parent?
class Parent { ... }
In child class:
#incude "Parent.h"
class Child : public Parent { <-- When I use this syntax, it says (essentially) that Parent is unknown.
}
OK, here is all of the code written again and tighter yet, on a single page. There is the INO file and Parent, Child and Grandchild which should lay the problem out clearly:
#ifndef _PARENT_h
#define _PARENT_h
#include "arduino.h"
// Derived class being created
#include "Child.h"
class ParentClass {
public:
ChildClass * child;
void init() {
child = new ChildClass;
}
};
extern ParentClass parent;
ParentClass parent;
#endif
Child Code:
#ifndef _CHILD_h
#define _CHILD_h
#include "arduino.h"
// Include parent of this class
#include "Parent.h"
// Include child being created
#include "GrandChild.h"
class ChildClass : public ParentClass {
public:
GrandChildClass * grandChild;
void init() {
grandChild = new GrandChildClass;
}
};
extern ChildClass child;
ChildClass child;
#endif
GrandChild Code:
#ifndef _GRANDCHILD_h
#define _GRANDCHILD_h
#include "arduino.h"
// Include parent of this class
#include "Child.h"
class GrandChildClass : public ChildClass {
public:
void init() {};
};
extern GrandChildClass GrandChild;
GrandChildClass grandChild;
#endif
And Compiler output:
Child.h:8: In file included from
Parent.h:6: from
ParentChild.ino:1: from
GrandChild.h: 9:43: error: expected class-name before '{' token
class GrandChildClass *: public ChildClass {
Parent.h:6: In file included from
ParentChild.ino:1: from
Child.h: 9:39: error: expected class-name before '{' token
class ChildClass *: public ParentClass {
Using previously compiled file: C:\Users\rhjon\AppData\Local\Temp\VMBuilds\ParentChild\uno\Release\Foo.cpp.o
Error compiling project sources
Build failed for project 'ParentChild'
So I've taken another look at your code and actually compiled the code in the original post.
Your issue is that you have circular dependencies in your header files. You can break those dependencies fairly easily by forward declaring your classes, which works as long as the compiler doesn't need to know the structure of the class such as when you are only declaring a pointer to it.
In Controller.h replace the two includes with forward declarations:
class GenericGetter;
class GenericPutter;
In GenericPutter.h replace the include with the forward declaration:
class Putter;
In GenericGetter.h replace the include with the forward declaration:
class Getter;
Make sure you include Controller.h in GenericPutter.h & GenericGetter.h.
Now in the cpp files you need to include the additional header files: GenericPutter.cpp
#include "GenericPutter.h"
#include "Putter.h"
GenericGetter.cpp
#include "GenericGetter.h"
#include "Getter.h"
In GenericPutter.h (and the equivalent in the getter) you have declared and defined a variable Putter *putter;. If that header file is included by multiple compilation units, then you will get multiple copies of the same variable and linking will fail.
You just want to declare the variable in the header file like this extern Putter *putter; and then define it once in one of the cpp files, ie. GenericPutter.cpp.
That should be enough to get your code to compile, however, I still think your structure is strange and you should give it some more thought.
Normally when you are using inheritance you are looking for "substitutability" - an "is a type of" relationship. A car is-a-type-of vehicle. A square is-a-type-of polygon.
In your case, you have a GenericGetter is-a-type-of Controller. Does that make sense to you for your intended project goal? To me it sounds odd.
Thank you for your great help. I am getting clearer and closer, but not all the way there yet. You are correct in your assumption that I am trying to implement an "is a" construct. I rewrote my code (attached) in the form of "Getters" and "Putters". In this case, a getter delivers data from a source and a putter takes that data and puts it somewhere. I implemented two getters (Joystick and Slider) and two putters (L298N and L9110) which are both H-Bridge motor controllers. So what I want to do is control either type of H-Bridge using either a Joystick or a pair of sliders. Ultimately, there could be many different getters and many different putters.
In the attached code, I am down to four errors:
Severity Code Description File Line
Error 12:3: error: 'putter' was not declared in this scope D:\Documents\Arduino\GetterPutter\Controller.cpp 12
Error 11:6: error: 'getter' was not declared in this scope D:\Documents\Arduino\GetterPutter\Controller.cpp 11
Error 10:1: error: expected class-name before '{' token D:\Documents\Arduino\GetterPutter\GetterJoystick.h 10
Error 10:1: error: expected class-name before '{' token D:\Documents\Arduino\GetterPutter\PutterL298N.h 10
I am puzzled by the first two: getter and putter appear to be declared in Controller.h at lines 24 and 32.
The other errors are the same as the ones I have been battling all along. I have tried to follow your recommendations but I seemed to have missed something along the way.
With regard to the first two error messages: When you split your code into separate cpp modules, each of the cpp modules is compiled separately, likewise the ino file (multiple inos are concatenated together before compilation). When you put #define GETTER_JOYSTICK true in your ino file it only applies to the ino file. Hence, when compiling the other modules, the define does not exist and so neither does getter.
There are various ways of solving this. It may be easiest for you to create a separate header file with project defines in it and include it at the beginning of each header file.
The second two error messages relate to your class model:
class GetterJoystick : public Controller ...
...
class Controller
{
public:
GetterJoystick getter;
So a GetterJoystick inherits from a Controller but a Controller contains a GetterJoystick? Not gonna happen.
You could make it (and the corresponding putters) pointers and then do the forward declare thing again, but I still don't understand why a GetterJoystick would have to inherit from a Controller.
You may be over-engineering yourself into insanity.
arduarn
, Perhaps you have identified why I have been feeling so crazy lately! Actually I have a very clear vision of what I want to accomplish, but I am frustrated by my inability to express what I want to do in C++. Ultimately, I want to build devices that have a getter and a putter and that sit inside the Arduino loop function. Exactly which getter and which putter are used for a specific device are defined in "config,h" which I added to the code.
I re-purposed Controller, added GenericGetter and GenericPutter and it now compiles and mostly works. What I am concerned about is that given my lack of clarity about how C++ works, have I now approached it in a good way? What could I do better?
Just a note about executing this code: It should work just fine except that if you enter text into the serial monitor, the putter makes a call to showData which doesn't see the data just entered. I am puzzling on that one; but my big question is about overall architecture / design. What would make it better?
rhj4:
Actually I have a very clear vision of what I want to accomplish, but I am frustrated by my inability to express what I want to do in C++. Ultimately, I want to build devices that have a getter and a putter and that sit inside the Arduino loop function. Exactly which getter and which putter are used for a specific device are defined in "config,h" which I added to the code.
I re-purposed Controller, added GenericGetter and GenericPutter and it now compiles and mostly works. What I am concerned about is that given my lack of clarity about how C++ works, have I now approached it in a good way? What could I do better?
Usually folks try to solve a problem; problem first, solution follows.
It sound to me like you have a solution, "I want to build devices that have a getter and a putter and that sit inside the Arduino loop function", with no problem (apart from struggling with the solution).
Solve some specific concrete problem first, learn while doing, then try to generalise it afterwards.
In any case, I would scrub the Controller class; I don't think you have shown enough shared characteristics for both the getters and putters to be inheriting from the same class. Maybe just stick with the GenericGetter and GenericPutter as parents.
rhj4:
Just a note about executing this code: It should work just fine except that if you enter text into the serial monitor, the putter makes a call to showData which doesn't see the data just entered. I am puzzling on that one;
I think you are misunderstanding inheritance. Both your GetterJoystick and PutterL298N classes logically inherit from Controller and therefore have a char _buffer at their base. However, when you create instances of GetterJoystick and PutterL298N, each have their own inherited Controller and therefore their own _buffer. If you fill GetterJoystick's _buffer with serial input, it is not magically propagated to PutterL298N's _buffer.
Also with regard to inheritance, you are looking for shared properties and behaviours for base classes. Since PutterL298N also inherits from Controller it also has a getSerialInput() function, which sounds more like a getter behaviour.
Delta_G:
Please post your individual files either inline or as attachments.
arduarn, I want to thank you for your help and feedback. I am now off and running and making great progress.
And to Delta_G' comment that " absolutely no reason why they would need to be zipped other than trying to severely limit the number of people who can help.", I can think of an excellent reason: There are now over 3,700 lines of code in over 50 separate files. The example I posted was considerably smaller, but still, there were a good number of files.
And I did try to configure my personal website to store the files there; but after an hour of messing with it, I gave up.
So my comment, Delta_G is that you may find it useful to be less quick to judge others.