Interdependent classes in different .cpp files: "Class does not name a type"

Hello,

I'm used to designing with an MVC-like pattern in which a core class creates an instance of an extension class, handing the extension a pointer to itself, so that the extension can call the core class' methods. When I try to do this in Arduino, it complains that the class name doesn't name a type. The header files containing all class prototypes are included both in the main sketch file, AND all .cpp files, in which the classes live.

I looked through Google for awhile. There was some advice to use include statements, like #include "../../Extension.h", but I think that's particular to earlier Arduino versions as the compiler complains that the file can't be found if I do that. It makes no complaint when I don't try to use relative paths. So, it's reading the header files, but apparently it doesn't believe what it sees?

The error is,

In file included from Core.h:5,
                from Core.cpp:2:
Extension.h:9: error: 'Core' does not name a type
Extension.h:10: error: expected `)' before '_theCore'

This is the main sketch, and other files in the same directory:

#include <Arduino.h>
#include "Core.h"
#include "Extension.h"

void setup() {
    // This will call Core(), which will instantiate Extension.
    // Extension's constructor takes a reference to Core, which
    // it then uses to ask it for a variable.
    Core theCore = Core();
}

void loop() {
}
#include <Arduino.h>
#include "Core.h"
#include "Extension.h"

Core::Core() {
    theExtension = Extension(this);
}

int Core::getVariable() {
    return 5;
}
#ifndef CORE_H
#define CORE_H

#include <Arduino.h>
#include "Extension.h"

class Core {
  public:
    Extension theExtension;
    int getVariable();
};

#endif
#include <Arduino.h>
#include "Core.h"
#include "Extension.h"

Extension::Extension(Core _theCore) {
    theCore = _theCore;
    Serial << theCore.getVariable();
}
#ifndef EXTENSION_H
#define EXTENSION_H

#include <Arduino.h>
#include "Core.h"

class Extension {
  public:
    Core theCore;
    Extension(Core _theCore);
};

#endif

Add a forward declaration to the Core class in extension.h

Why?

core.h includes extension.h, so even though extension.h includes core.h, class Extension is declared before class Core, which it uses 'before it is defined', and subsequently does not name a type. :slight_smile:

I could be wrong, but give it a try.

#ifndef EXTENSION_H
#define EXTENSION_H

#include <Arduino.h>
#include "Core.h"

class Core;

class Extension {
public:
Core theCore;
Extension(Core _theCore);
};

#endif

Pretty sure that won't work Pyro.

What will work is an interface class - a pure virtual class, which acts as an arbitrator between parent and child types.
Some people claim interfaces are the correct way. Bloody long winded way if you ask me.

The sketch

#include "Core.h"
Core* theCore;
void setup() {
	Core* theCore = new Core();
	theCore->getExtension()->foo(1);
	Serial.println(theCore->getExtension()->bar());
}

The parent class inherits and implements the interface

#ifndef __CORE_H__
#define __CORE_H__
#include "Extension.h"

class Core : public ifCore {
protected:
	Extension* extension;
	int var1;
public:
	Core() {extension = new Extension(this);}
	~Core();
	Extension* getExtension() {return extension;}
protected:
		int getVar1() {return var1;}
		void setVar1(int value) {var1 = value;}
};
#endif //__CORE_H__

Then interface class defines those parts of the parent accessible to the child

#ifndef __IFCORE_H__
#define __IFCORE_H__

class ifCore {
public:
	virtual ~ifCore(){}
	virtual int getVar1() = 0;
	virtual void setVar1(int) = 0;
};
#endif //__IFCORE_H__

And finally the child class, gets to use those parts of the parent, the parent has allowed it to.

#ifndef __EXTENSION_H__
#define __EXTENSION_H__
#include "ifCore.h"

class Extension {
	public:
		ifCore* parent;
	public:
		Extension(ifCore* parent_) {parent = parent_;}
		void foo(int a) {parent->setVar1(a + 1);}
		int bar() {return parent->getVar1();}
		~Extension();	
};
#endif //__EXTENSION_H__
[/quote]

626Pilot:
I'm used to designing with an MVC-like pattern in which a core class creates an instance of an extension class, handing the extension a pointer to itself, so that the extension can call the core class' methods.

That sort of mutual dependency looks wrong to me. It seems as if you're trying to put the factory inside the product. If you separate out these abstractions you remove the need for any mutual dependency. If you really want both abstractions in the same class then define an interface which your extension class uses to access the core class so that you do not have a mutual dependency between the factory/core and the extension

MattS-UK:
Pretty sure that won't work Pyro.

No, it doesn't by itself. However thankfully there is no need for a base class of virtual functions either.

By changing theExtension & theCore to pointers ( removing the need for the headers until the cpp files ) and using forward declarations like I mentioned ( for both classes ) the problem is solved far easier.

PeterH:
That sort of mutual dependency looks wrong to me.

It works quite well in the field! I've been using it for ages, but in other programming languages. The pattern I use here looks like a star topology, in which the Core is the central hub, and the Extensions are contained within it, and talk to it, and to each other, through it. For example, if I'm rendering a web page, Core will contain things like User and View. Code in a Web template will cause View to query Core.User.userName for the name of the logged-in user. Likewise, if the user changes their username, the View can tell Core.User to make it happen. This is arbitrated through strict access rules and thorough input sanitization.

This may bear some similarities to things in the Design Patterns book, and I'm sure it could violate some principle therein. I don't use it all the time, but where it fits, it works REALLY well.

MattS-UK:
What will work is an interface class - a pure virtual class, which acts as an arbitrator between parent and child types.
Some people claim interfaces are the correct way. Bloody long winded way if you ask me.

Thank you VERY much!!! This works as it should.

I split off the .h files with inline methods into .h/.cpp. I also had to remove the ~Core(); from the ifCore.h prototype because it was causing it not to compile. And now it DOES compile!

And what size does it compile? ( what board too )

626Pilot:
It works quite well in the field! I've been using it for ages, but in other programming languages.

Same here, used it in other languages. It's quite a powerful form of polymorphism and very useful in event driven systems.

My own little speciality is networks, where I might have an over arching server object, spawning multiple connection objects, which all need to tell the server when certain things happen, like a timeout for instance. Essentially, an interface is an appropriate method for many different things (types) refreshing a single state machine. For a single type, I think it is a bit long winded and introduces an additional layer of complexity at design time. With C/C++ you can probably avoid the need for an interface by passing a pointer to a function.

I split off the .h files with inline methods into .h/.cpp. I also had to remove the ~Core(); from the ifCore.h prototype because it was causing it not to compile. And now it DOES compile!

Interesting. I compiled the example as far as creating an instance of Core. I didn't try to run it on a board. Whilst I wrote the example, it was in the back of my mind that if I ever used it for real, I would want to be very certain objects were destroyed as they should be.

Anyhow, nice to see a bit of OOP in the Arduino forum :slight_smile:

@pyro. Here is what I get when I compile the example

Compiling 'Core1' for 'Arduino Yún'
Binary sketch size: 6042 bytes (used 21% of a 28672 byte maximum) (4.25 secs)
Minimum Memory Usage: 185 bytes (7% of a 2560 byte maximum)

AVR Memory Usage
----------------
Device: atmega32u4

Program:    6042 bytes (18.4% Full)
(.text + .data + .bootloader)

Data:        185 bytes (7.2% Full)
(.data + .bss + .noinit)

text	   data	    bss	    dec	    hex	
      0	   6042	      0	   6042	   179a