Fairly new to design patterns, maybe I've missed the answered question already. I'm having trouble practicing the factory design pattern due to an inheritance issue.
This is the base class
#ifndef FACTORY_H
#define FACTORY_H
#include <iostream>
#include "truckfactory.h"
class factory{
public:
std::string typeOfCar;
factory(){}
virtual void identifyCar(){
std::cout << "This car is a " + typeOfCar << std::endl;
}
truckfactory* createTruck(){
return new truckfactory();}
};
#endif
And this is the subclass of the base factory class.
#ifndef TRUCKFACTORY_H
#define TRUCKFACTORY_H
#include "factory.h"
class truckfactory : public factory{
public:
truckfactory(){
std::cout <<"TruckFactory made"<<std::endl;
typeOfCar = "truck";
}
};
#endif
Trying to implement as such
#include "factory.h"
int main(){
factory carFactory;
truckfactory* truck;
truck = carFactory.createTruck();
carFactory.identifyCar();
truck->identifyCar();
return 0;
}
However I run into the following issues
./truckfactory.h:5:29: error: expected class name
class truckfactory : public factory
^
./truckfactory.h:11:13: error: use of undeclared identifier 'typeOfCar'
typeOfCar = "truck";
^
factorytest.cpp:10:12: error: no member named 'identifyCar' in 'truckfactory'
truck->identifyCar();
I was looking around at other inheritance issues, but I couldn't find one that solves what I'm looking at.
Thanks for the help, and sorry if it's a repost
There are a few things to consider:
The reason your code won't compile is due to its structure. You can't (or shouldn't) have factory.h include truckfactory.h, which then includes factory.h. The circular dependency will cause you problems. The normal way of handling this is to forward declare truck_factory like this:
#ifndef FACTORY_H
#define FACTORY_H
#include <iostream>
class truck_factory;
class factory{
public:
std::string typeOfCar;
factory(){}
virtual void identifyCar(){
std::cout << "This car is a " + typeOfCar << std::endl;
}
truckfactory* createTruck(); //Note definition must be in c++ file
};
#endif
Conceptually your factory should build objects, not other factories. For example, you might have a class factory which knows how to build trucks, car, motorbikes etc. To do this you would want to define a vehicle class and then a factory which can build the correct class based on the type passed in. Something like:
class Vehicle {
public:
virtual std::string typeOfCar() const = 0;
void identifyCar() {
std::cout << "This car is a " + typeOfCar << std::endl;
}
};
class Factory {
public:
Vehicle* create_vehicle(const std::string& type); // need to somehow specify what type you want to create.
};
class Truck : public Vehicle {
virtual std::string typeOfCar() const { return "truck"; }
};
The create_vehicle function would need to be defined in a cpp file to return various vehicle types.
Related
I got two classes separated in four files. The main class includes a sub class and needs to execute functions of it (not shown in the minimal example code). What I want to do is to execute a function of the main class in the scope of the subclass.
I think some ideas would be to inherit the functions in the sub class but I could not figure out how to do this.
MainClass.cpp
#include "MainClass.hpp"
void MainClass::mainCallback() {
std::cout << "[mainCallback] executed" << std::endl;
}
void MainClass::subCallback() {
std::cout << "[subCallback] executed" << std::endl;
}
int main() {
MainClass mainClass;
mainClass.mainCallback();
SubClass subClass;
subClass.activateSubClass();
return 0;
}
MainClass.hpp
#pragma once
#include "SubClass.hpp"
#include <iostream>
class MainClass{
public:
void mainCallback();
void subCallback();
};
SubClass.cpp
#include "SubClass.hpp"
void SubClass::activateSubClass(){
mainClass.subCallback(); //TODO call this function from this scope
}
SubClass.hpp
#pragma once
class SubClass{
public:
void activateSubClass();
};
The error in SubClass.cpp is of course:
error: use of undeclared identifier 'mainClass'
Just subclass the subclass:
class SubClass: public MainClass {
public:
void activateSubClass();
};
This (public) way the SubClass makes all methods of MainClass callable in SubClass instances. You could also private inherit. That way only activateSubClass() 'ld be callable.
In activateSubClass you can call directly the methods of the parent class:
void SubClass::activateSubClass(){
mainClass.subCallback(); //TODO call this function from this scope
}
Don't forget to include MainClass.hpp in SubClass.hpp
You try to call a MainClass.subCallback() without having an instance of MainClass. According to me, this is the typical use case for static methods.
Then, I think you make your #include directives the wrong way. Indeed, MainClass does not seem to need to know SubClass but the opposite is true. I think it is better to include MainClass.hpp in SubClass.hpp. This will solve your circle dependencies problem.And you can write your main() function in another file.
EDIT: Example
MainClass.hpp:
#pragma once
class MainClass
{
public:
void mainCallback();
static void subCallback(); // mak it static to be able to call it without an instance of the class
};
MainClass.cpp:
#include "MainClass.hpp"
#include <iostream>
void MainClass::mainCallback()
{
std::cout << "[mainCallback] executed" << std::endl;
}
void MainClass::subCallback()
{
std::cout << "[subCallback] executed" << std::endl;
}
SubClass.hpp:
#pragma once
class SubClass
{
public:
void activateSubClass();
};
SubClass.cpp:
#include "SubClass.hpp"
#include "MainClass.hpp" // MainClass inclusion
void Suclass::activateSubClass()
{
MainClass::subCallback(); // Call of the static method
}
main.cpp:
#include "MainClass.hpp"
#include "SubClass.hpp"
int main()
{
MainClass mc;
mc.mainCallback();
SubClass sc;
sc.activateSubClass(); // Will call MainClass::subCallback()
return 0;
}
I hope it can help you.
node.h:
#include "tree_node.h"
class tree_node_t;
class node_base : public tree_node_t
{
public:
node_base();
~node_base();
};
tree_node.h:
#include "node.h"
class node_base;
class tree_node_t
{
tree_node_t();
std::vector<node_base*> list;
. . .
}
Everything looks seems to be correct, but for some reason I get the error "invalid use of incomplete type ‘class tree_node_t’". I don't understand why this is happening.
As far as I understand, the solution to these problems is to split the files into headers (.h) and source code files (.cpp). Divided, but continue to receive such a mistake.
You can't inherit from an incomplete type. The compiler needs to have the full definition of tree_node_t when inheriting from it in order to correctly determine the size of the class as well as the offset of the data members.
But by putting class tree_node_t; after already having included the header you shadow the definition that the compiler needs. So just removing the line class tree_node_t; should make everyting compile fine, unless you're also missing include guards.
As correctly pointed out by Rudolfs Bundulis you also need to remove the #include "node.h" in tree_node.h because otherwise the code that gets passed to the compiler when including tree_node.h looks like this:
class node_base : public tree_node_t
{
public:
node_base();
~node_base();
};
class node_base;
class tree_node_t
{
tree_node_t();
std::vector<node_base*> list;
. . .
};
which can't compile because suddendly the definition of tree_node_t comes after the definition of node_base which tries to inherit from it.
natersoz and Markus was right. All I had to do was remove #include from tree_node.h.
As far as I understand, the solution to these problems is to split the
files into headers (.h) and source code files (.cpp).
Splitting the code into files is often the preferred solution. It is at least something good for you to practice.
Generally, however, one can still do this code in a single file, and in this case with one forward declaration.
The following compiles, links, and runs (but does very little):
#include <iostream>
using std::cout, std::flush, std::endl;
#include <vector>
using std::vector;
// in this ordering, the single forward suffices,
// because all class pointers are a known size,
// and
// this symbol (as yet) is only in the tree_node_t data,
// in the vector as a pointer
class node_base_t;
class tree_node_t
{
// private data attributes
vector<node_base_t*> list;
// tbd ... other data
public:
tree_node_t() // default ctor
// : list ctor is ok
{
cout << "\n tree_node_t() " << flush;
}
~tree_node_t() = default; // dtor
// tbd ... more public functions
private:
// tbd ... private functions
};
class node_base_t : public tree_node_t
{
// private data
// ... tbd - other data
public:
node_base_t() // tree_node_t default ctor is ok
{
cout << "\n node_base_t() " << flush;
}
~node_base_t() = default;
// tbd ... more public functions
private:
// tbd ... private functions
};
int main(int , char** )
{
int retVal = -1;
{
node_base_t nb;
retVal = 0;
}
cout << "\n" << endl;
return retVal;
}
output:
tree_node_t()
node_base_t()
Because of virtual inheritance, when the write() function from the
transmitter class is called, the method read() from the receiver class
gets called (as you may have noticed, the transmitter class doesn't
have a read() function). In the above hierarchy we can instantiate
only the radio class because transmitter and receiver are abstract due
to virtual inheritance.
http://www.cprogramming.com/tutorial/virtual_inheritance.html
So I tried it and it didnt worked for me.
#pragma once
#include <iostream>
using namespace std;
father class:
class father
{
public:
father(){
};
~father(){};
virtual void printt() = 0;
void sett()
{
printt();
}
void father()
{
cout << "Im your father...";
}
private:
};
Person:
#pragma once
#include <iostream>
using namespace std;
#include "father.h"
class MyClasst: public virtual father
{
public:
MyClasst(){
g = 8;
};
~MyClasst(){};
void print()
{
cout << "a";
}
void c()
{
cout << "bbb";
}
private:
...
};
Student class:
#pragma once
#include <iostream>
#include "father.h"
using namespace std;
class MyClassa: public virtual father
{
public:
MyClassa(){
};
~MyClassa(){};
void printt()
{
cout << "b";
}
void b()
{
c();
printt();
}
private:
...
};
By the rules above, I should be able to call 'c()' from person class in 'b()' ('b()' is function of Student which is virtual brother of 'Person class').
But I get an error:
Error 1 error C3861: 'c': identifier not
found c:\users\micha\onedrive\מסמכים\visual studio
2013\projects\project7\project7\student.h 21 1 Project7
This is because the "c()" function is not declared in the base class "father" and your class "MyClassa" derives only from "father".
Consequently, an object of class "MyClassa" will not contain any function "c()".
An object of a class deriving from "MyClasst" (as well as an object deriving from both "MyClassa" and "MyClasst" will have it).
If you want to have your code compiling, you must add a declaration of "c()" in the parent class. Add the line "virtual void c() = 0;" in the class "father" - then will compile. Live example here: http://rextester.com/OBBC17077
There is no method c() in MyClassa directly nor inherited from father. There is a method c() in MyClasst, but the two classes have no relation apart from inheriting both from father, but that doesnt allow them to call methods from each other.
Imho the analogy with the so called "parent class" and "child classes" does not make much sense and only leads to confusion. It doesnt make sense to say "a child is-a parent", but thats what (public) inheritance actually is. I would advice you to forget about the term "brother class". It doesnt help you to understand anything. And btw the error you get has little to do with the virtual inheritance. You would get the same error with public inheritance.
I'm having problems with my code with dynamic_cast. I have spent many hours trying to find a solution for this, but I still don't find the answer. I read that the problem could be because I didn't write forward declarations but I have already done that and still with the same problem.
Abstract class
#include "CRoute.h"
class CScreen
{
protected:
CRoute* m_pRoute;
public:
virtual ~CScreen();
virtual void connecToRoute(CRoute* route) = 0;
virtual void drawRoute() = 0;
};
Derived class
#include "CScreen.h"
class CGUIScreen : public CScreen
{
public:
void drawRoute();
void connecToRoute(CRoute* route);
};
Derived class
#include "CScreen.h"
class CCRTScreen : public CScreen
{
public:
void drawRoute();
void connecToRoute(CRoute* route);
};
Base Class
#include <string>
#include <iostream>
using namespace std;
class CScreen;
class CCRTScreen;
class CGUIScreen;
class CWaypoint
{
public:
CWaypoint();
void print(int format, CScreen* screenType);
};
Derived class
#include <iostream>
#include <string>
#include "CWaypoint.h"
using namespace std;
class CScreen;
class CCRTScreen;
class CGUIScreen;
class CPOI : public CWaypoint
{
public:
void print(int format, CScreen* screenType);
};
Method of CPOI
void CPOI::print(int format, CScreen* screenType)
{
if(dynamic_cast<CGUIScreen*>(screenType)) ---> Here is the error <<----
{
cout << "printing POI GUI " << endl;
}
else if(dynamic_cast<CCRTScreen*>(screenType)) ---> Here is the error <<----
{
cout << "printing POI CRT " << endl;
}
}
And the error I'm getting is the next one
..\myCode\CWaypoint.cpp:184:41: error: cannot dynamic_cast 'screenType' (of type 'struct CScreen*') to type 'struct CGUIScreen*' (target is not pointer or reference to complete type)
..\myCode\CWaypoint.cpp:184:44: error: expected unqualified-id before ')' token
..\myCode\CWaypoint.cpp:188:46: error: cannot dynamic_cast 'screenType' (of type 'struct CScreen*') to type 'struct CCRTScreen*' (target is not pointer or reference to complete type)
I read that the problem could be because I didn't write forward
declarations but I have already done that and still with the same
problem.
Quite the contrary; your forward declarations are what causes the errors.
A forward declaration, such as your class CScreen; line, simply tells the compiler: "There is a class called 'CScreen'. I'll give you more details later, but for now just keep in mind that this is a valid class name, OK?"
The compiler can then do very basic things with that class name; for example, it will accept pointer or reference declarations with it. That's why your print(int format, CScreen* screenType) line works. You don't need to know anything about CScreen other than its name to declare a pointer to it.
But how is the compiler supposed to accept a dynamic_cast with the class name? It does not really know anything about the class. In particular, it does not know that CGUIScreen or CCRTScreen are derived from CScreen. That's why at the point where you use dynamic_cast, the full class definitions are needed.
The header files for CWaypoint and CPOI (possible called waypoint.h and point.h?), can thus safely use forward declarations. As you correctly did:
waypoint.h:
class CScreen;
class CCRTScreen;
class CGUIScreen;
class CWaypoint
{
public:
CWaypoint();
void print(int format, CScreen* screenType);
};
point.h:
class CScreen;
class CCRTScreen; // not necessary but not invalid
class CGUIScreen; // not necessary but not invalid
class CPOI : public CWaypoint
{
public:
void print(int format, CScreen* screenType);
};
The implementation files, however, (possible called waypoint.cpp and point.cpp?), require the full definitions when you use a dynamic_cast:
point.cpp:
#include "point.h"
#include "screen.h"
#include "gui_screen.h"
#include "crt_screen.h"
#include <iostream>
using std::cout;
using std::endl;
void CPOI::print(int format, CScreen* screenType)
{
if(dynamic_cast<CGUIScreen*>(screenType))
{
cout << "printing POI GUI " << endl;
}
else if(dynamic_cast<CCRTScreen*>(screenType))
{
cout << "printing POI CRT " << endl;
}
}
By the way, it seems that CWaypoint should actually be an abstract base class, and that it possibly doesn't need an implementation file at all:
point.h:
class CScreen;
class CWaypoint
{
public:
virtual ~CWaypoint() {}
virtual void print(int format, CScreen* screenType) = 0;
};
P.S: If I may say so, I think your class names are confusing. A "Point" is definitely something more general than a "Waypoint", yet the inheritance relationship is exactly vice versa. Also, consider getting rid of Hungarian Notation. Just call your classes Screen instead of CScreen etc.
What the error message is telling you is that it does not know what the definition of CScreen or any of the derived classes are because you have forward declared them but not included their definitions.
Instead of
class CScreen;
class CCRTScreen;
class CGUIScreen;
Use
#include "CCRTScreen.h"
#include "CGUIScreen.h"
Trying to pass a parent class object to a child class object so that the child class object has control over the parent class object's methods.
This is however resulting in header related issues.
I've tried forward declaring one of the classes but it seems whatever class is declared first always has trouble reading from the class declared below.
Both errors refer to Device' constructor where try to call dm's hello world method, they are:
Use of undefined type 'DeviceManager'
Left of '->HelloWorld' must point to class/struct/union/generic type
...
//main.cpp
#include "parent.h"
void main()
{
cout << "Created DeviceManager\n";
DeviceManager* deviceManager = 0;
deviceManager = new DeviceManager;
cout << "Giving DeviceManager a device\n";
deviceManager->p = new Device(deviceManager);
cout << "Giving Device a reference to DevicenManager\n";
deviceManager->Share();
}
...
class DeviceManager;
class Device
{
public:
Device(DeviceManager* manager)
{
dm = 0;
this->dm = manager;
this->dm->HelloWorld();
}
DeviceManager* dm;
};
//device manager
class DeviceManager
{
public:
DeviceManager()
{
p = 0;
}
void HelloWorld()
{
//if this calls we know the child has control over the parent.
cout << "Hello World";
}
Device* p;
};
Yes.
To solve circular dependencies with class member and function declarations, you can forward-declare a class:
class A;
class B {
A *a;
};
class A {
B *b;
};
To define class member functions that access members of the other class, you must define the function after the other class has been defined:
class B;
class A {
public:
void f(B &arg);
};
class B {
public:
void g(A &arg);
};
void A::f(B &arg) {
arg.g(*this);
}
void B::g(A &arg) {
arg.f(*this);
}
Usually, in a C++ project, you wouldn't even encounter this problem: You would put function definitions, i.e. implementations, into .cpp files, while putting the class definitions into header files. Class forward declarations, if neccesary, could be put into their own header files that are included by all headers that need them.
A full example of how you would split the above code into multiple files:
a.cpp
#include "a.h"
#include "b.h"
void A::f(B &arg) {
arg.g(*this);
}
b.cpp
#include "b.h"
#include "a.h"
void B::g(A &arg) {
arg.f(*this);
}
a.h
#ifndef _A_H_
#define _A_H_
#include "forward_declarations.h"
class A {
public:
void f(B &arg);
};
#endif //_A_H_
b.h
#ifndef _B_H_
#define _B_H_
#include "forward_declarations.h"
class B {
public:
void g(A &arg);
};
#endif //_B_H_
forward_declarations.h
#ifndef _FORWARD_DECLARATIONS_H_
#define _FORWARD_DECLARATIONS_H_
class A;
class B;
#endif //_FORWARD_DECLARATIONS_H_
As a general rule of thumb, if you need to forward-declare a class, you might have misdesigned something and should think about whether there is a better way (but there also are perfectly valid use cases that require class forward declarations).
If you don't understand my #ifndef, #define and #endif preprocessor lines: These are header guards, and should be used with all files that are included somewhere else, exception you know precisely what you're doing. Believe me. You'll regret ommiting one.
If your problem is cyclic dependancy, like this:
// DeviceManager.h
#include "device.h"
class DeviceManager
{
DeviceManager(Device& device) {}
};
// Device.h
#include "DeviceManager.h"
class Device
{
Device(DeviceManager& manager) {}
};
You can solve the problem be forward declaring one of the classes, and passing the object by pointer.
// Device.h
//#include "DeviceManager.h"
class DeviceManager;
class Device
{
Device(DeviceManager* manager) {}
};