?
Solved

State Design Pattern in C++ "base class undefined"?

Posted on 2013-11-07
8
Medium Priority
?
512 Views
Last Modified: 2013-11-11
This works so easy in C#. Translating to C++ befuddles me.

The C++ compiler starts with file ConcreteStateA.h (I think it goes in alphabetical order) and it's complaining 'StateBase' : base class undefined

ConcreteStateA.h
#pragma once
#include "StateBase.h"

class ConcreteStateA : public StateBase
{
	public:
		virtual void Handle(MyContext *context) override;

};

Open in new window

But I have #include StateBase.h which is where class StateBase is defined. So why isn't this working?

StateBase.h
#pragma once
#include "MyContext.h"

class StateBase
{
	public:
		virtual void Handle(MyContext *context) = 0;
};

Open in new window

MyContext.h
#pragma once
#include "StateBase.h"
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"

class MyContext
{
	private:
		class StateBase *_state;
	public:
		ConcreteStateA *a;
		ConcreteStateB *b;

		void Request();

		const StateBase &getState() const;
		void setState(const StateBase &value);

	private:
		void InitializeInstanceFields();
};

Open in new window

0
Comment
Question by:deleyd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
8 Comments
 
LVL 35

Assisted Solution

by:sarabande
sarabande earned 1004 total points
ID: 39632077
the problem is that mycontext.h is including statebase.h and statebase.h is including mycontext.h.

obviously that is a circular inclusion.

concretestatea.h
    includes statebase.h
       includes mycontext.h
            tries to include statebase.h but fails because of pragma once            
            tries to include concretestatea.h but fails because of pragma once
            includes concretestateb.h
                 .... ?
            defines class MyContext
                    fails to use StateBase *_state member cause class StateBase is not declared yet.

the way out is to include only in hierarchical order. you can declare pointers of a class where the header is not included by using a forward declaration:

// mycontext.h

// forward declaration
class StateBase;

class MyContext
{
      // pointer and reference of StateBase can be used
      StateBase  * pStateBase;
      ...

Open in new window


Sara
0
 
LVL 29

Assisted Solution

by:pepr
pepr earned 996 total points
ID: 39632082
The StateBase class declares the method
virtual void Handle(MyContext *context) = 0;

Open in new window

as abstract one. It means there is no implementation. The derived class must define the body of the method.

The override reveals that the code follows the C++11 standard. It says the base class must declare the same virtual function (i.e. with the same signature), and that the derived class must implement it.

Update: Sara is right.
0
 
LVL 35

Assisted Solution

by:sarabande
sarabande earned 1004 total points
ID: 39632107
This works so easy in C#. Translating to C++ befuddles me.
actually it is the C precompiler which is responsible for the difference.

header files are included sequentially in c and c++ and can be controlled by macros (or pragma statements). the concept cannot be abandoned as long as c++ is a superset of c.

Sara
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:deleyd
ID: 39634745
Forward Declarations. I see that's the concept I was missing.

I'm thinking the # pragma once would take care of the circular references?

I'm making progress. Still having some C++ syntax problems. I removed the override keyword. What does the virtual keyword mean in that same line? (Line 7 below)

ConcreteStateA.h
#pragma once
#include "StateBase.h"

class ConcreteStateA : public StateBase
{
	public:
		virtual void Handle(MyContext *context);
};

Open in new window

StateBase.h (Note I commented out #include "MyContext.h" and replaced with Forward Declaration
#pragma once
//#include "MyContext.h"

class MyContext;

class StateBase
{
	public:
		virtual void Handle(MyContext *context) = 0;
};

Open in new window

MyContext.h
#pragma once
#include "StateBase.h"
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"

//forward declaration
class StateBase;

class MyContext
{
  public:
  MyContext();

	private:
		class StateBase *_state;
	public:
		ConcreteStateA *a;
		ConcreteStateB *b;

		void Request();

		const StateBase &getState() const;
		void setState(const StateBase &value);

	private:
		void InitializeInstanceFields();
};

Open in new window

MyContext.cpp
#include "StdAfx.h"
#include "MyContext.h"
#include "StateBase.h"
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"

MyContext::MyContext(void)
{
		InitializeInstanceFields();
		_state = a;
}

	void MyContext::Request()
	{
		_state->Handle(this);
	}

	const StateBase &MyContext::getState() const
	{
		return _state;
	}

	void MyContext::setState(const StateBase &value)
	{
		_state = value;
	}

	void MyContext::InitializeInstanceFields()
	{
		a = new ConcreteStateA();
		b = new ConcreteStateB();
	}

Open in new window

Line 20 above is giving me error cannot convert from 'StateBase *const ' to 'const StateBase &'
Simmilarly, line 25 is giving me error cannot convert from 'const StateBase' to 'StateBase *'

ConcreteStateA.cpp
#include "StdAfx.h"
#include <iostream>
#include <string>
#include "ConcreteStateA.h"
#include "MyContext.h"


	void ConcreteStateA::Handle(MyContext *context)
	{
		std::cout << std::wstring(L"Handle called from ConcreteStateA") << std::endl;
		//context.State = new ConcreteStateB();
		context->setState(context->b);
	}

Open in new window

Line 10 above is giving me error about the << symbol.
Line 12 is giving me error: cannot convert from 'ConcreteStateB *' to 'const StateBase' in reference to the context->b
0
 
LVL 29

Assisted Solution

by:pepr
pepr earned 996 total points
ID: 39636272
On virtual methods (informally).

A method of the object is a function that can be applied to the object itself and to the passed arguments. That should be clear enough.

If both base and derived classes define the same kind of method (same signature, i.e. the same name and arguments), then the base class defines its own body for the method, and the derived class may define another one. When the object of the derived class exists and it calls its own method, it will use the code defined in the derived class. It can also explicitly call the code of the same method from the base class. In other words, a different code for both methods exists in parallel and can be used. However, implicitly, the object uses the code of its own class and ignores the code of the base class. We name it overloading.

What is important, the base class has no chance to know the method code of the derived class. The base class is more general, and there may be more of the specialized classes, each one overloading the code of the method differently. Anyway "it would be good if another method of the base class could call the well known method that would behave depending on the specialization". To do that, the base-class code have to learn what is the correct code to be called. It should get a pointer to the code, and the pointer should be directed to the code of the specialized class.

There is a table of such "pointers" and the table is called a virtual table. The keyword virtual says to the compiler that exactly this method should be threated the above described way. Virtual methods are the ones where even the base class  methods know how to call the specialized functionality.
0
 

Author Comment

by:deleyd
ID: 39636345
Wow sounds complicated; yet it makes sense, most of it. So just keep the virtual keyword there I guess.

How about those 4 lines giving me syntax errors?
0
 
LVL 29

Assisted Solution

by:pepr
pepr earned 996 total points
ID: 39638147
For virtual, it is enough to use the keyword only in the base class. Anyway, it is recommended to use it also in the derived classes as a reminder.

For the errors, whenever you restrict something to const, you cannot use it as non-const (or offer it as non-const to be used in another code). The compiler does not allow it. For the quick hack, you can remove the const modifier. However, if it is not your code, you should probably better think about the reasons.
0
 
LVL 35

Accepted Solution

by:
sarabande earned 1004 total points
ID: 39638358
I'm thinking the # pragma once would take care of the circular references?

Open in new window


the #pragma once makes sure that a header file is not included twice. by doing that it also prevents from circular including. but that doesn't handle the order of inclusions what is crucial in c/c++ as symbols (like class names) only can be used if they were declared or defined before.

alternatively to the #pragma you can do

#ifndef HEADER_H
#define HEADER_H
...
// put here the contents of the header file
...
#endif

Open in new window

what has the advantage that it is portable.

Wow sounds complicated; yet it makes sense, most of it. So just keep the virtual keyword there I guess.
virtual functions is the key principle of c++ and other object-oriented languages. it makes it possible to derive from an existing class an enhance that class by writing new or additional code for all functions where the design of the base class allows doing so. so the designer of a (possible) base class wouldn't add the virtual to all functions but only to those where they want allow a customization or where they want to promote a further specialization.

Sara
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

800 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question