The idea is this: I have SportsCar derived from Car, a Car consists of an Engine, each time Car.drive() is called, it calls Engine.consumeGas(), which in turn creates a Gas object and calls Gas.burn(). As you can see in the source code below.
Each class has its own header file and cpp file. And I wrote a Makefile (for Microsoft's NMAKE program).
The dependency is like this:
test.exe: main.obj Car.obj SportsCar.obj Engine.obj Gas.obj
main.obj: main.cpp Car.h SportsCar.h
Car.obj: Car.cpp Car.h
SportsCar.obj: SportsCar.cpp SportsCar.h // Here is what went wrong
Engine.obj: Engine.cpp Engine.h Gas.h
Gas.obj: Gas.cpp Gas.h
Build the program and run test.exe, produced the output:
Car drive
Engine consuming gas
Gas burning
SportsCar drive
Engine consuming gas
Gas burning
The problem is if I delete the member engine from Car and delete the call engine.consumeGas() in Car.drive() and rebuild the whole program, only Car.cpp and main.cpp are recompiled (SportsCar.cpp is not) and the linker won't complain at all.
After rebuilding, run test.exe get the output:
Car drive
SportsCar drive
Engine consuming gas
Gas burning
Apparently this result has completely violated the semantics of C++.
If I write the dependency like this, the problem will be fixed.
SportsCar.obj: SportsCar.cpp SportsCar.h Car.h
So if I have one source file A which includes a header file B, which in turn includes another header file C, and in A, the class C is used, I have to say A depends on both B and C, not just A depends on B?
If the project is large enough, I'm afraid I'll get lost trying to find out which file depends on which file while writing a Makefile.
Code:
main.cpp
#include "Car.h"
#include "SportsCar.h"
int main()
{
Car *car = new Car();
car->drive();
delete car;
car = new SportsCar();
car->drive();
delete car;
return 0;
}
Car.h
#ifndef CAR_H
#define CAR_H
#include "Engine.h"
class Car
{
protected:
Engine engine;
public:
virtual void drive();
virtual ~Car();
};
#endif // CAR_H
Car.cpp
#include "Car.h"
#include <iostream>
using namespace std;
void Car::drive()
{
cout << "Car drive" << endl;
engine.consumeGas();
}
Car::~Car()
{
// do nothing
}
SportsCar.h
#ifndef SPORTSCAR_H
#define SPORTSCAR_H
#include "Car.h"
class SportsCar : public Car
{
public:
void drive();
};
#endif // SPORTSCAR_H
SportsCar.cpp
#include "SportsCar.h"
#include <iostream>
using namespace std;
void SportsCar::drive()
{
cout << "SportsCar drive" << endl;
engine.consumeGas();
}
Engine.h
#ifndef ENGINE_H
#define ENGINE_H
class Engine
{
public:
void consumeGas();
};
#endif // ENGINE_H
Engine.cpp
#include "Engine.h"
#include "Gas.h"
#include <iostream>
using namespace std;
void Engine::consumeGas()
{
cout << "Engine consuming gas" << endl;
Gas g;
g.burn();
}
Gas.h
#ifndef GAS_H
#define GAS_H
class Gas
{
public:
void burn();
};
#endif // GAS_H
Gas.cpp
#include "Gas.h"
#include <iostream>
using namespace std;
void Gas::burn()
{
cout << "Gas burning" << endl;
}
You should generally never hardcode dependencies into makefiles. Instead, you should use the -M -MF flags to generate the dependencies during compilation and include the resulting file into your Makefile. Otherwise your dependencies will always be out of sync with reality.
Sadly, automatic dependency generation is a complex topic which I can't explain here in full detail. Many of the details can be found in this article: Auto-Dependency Generation
Related
all! I am trying to create a very simple inheritance structure using C++ and header files but (of course) I am having some difficulties.
When I try to compile my main program, I get this error:
In function `Base::Base()':
undefined reference to 'vtable for Base'
In function `Derived::Derived()':
undefined reference to 'vtable for Derived'
All I want is to print is
printed in Derived
but I am having some extreme difficulties.
Here are my program files:
main.cpp
#include <iostream>
#include "Base.h"
#include "Derived.h"
using namespace std;
int main(void) {
Base *bp = new Derived;
bp->show();
return 0;
}
Base.cpp
#include <iostream>
#include "Base.h"
virtual void Base::show() {
cout << "printed in Base";
}
Base.h
#ifndef BASE_H
#define BASE_H
class Base {
public:
virtual void show();
};
#endif
Derived.cpp
#include <iostream>
#include "Derived.h"
using namespace std;
void Derived::show() override {
cout << "printed in Derived";
}
Derived.h
#ifndef DERIVED_H
#define DERIVED_H
class Derived: public Base {
public:
void show() override;
};
#endif
Thank you! And any help is very much appreciated!...extremely.
As pointed out in the comments, by calling g++ main.cpp you are only compiling main.cpp.
You need to compile all files, then link them together. If you do so, you will see that there are compilation issues in your other cpp files as also pointed out in the comments (virtual and override only belong in the header).
So you need to call the following to compile all files:
g++ main.cpp Base.cpp Derived.cpp -o myapp
I've been programming a Monopoly game for a final project. So I thought I was on a roll, and that I had everything figured out with my psuedocode. But, it seems I forgot how to deal with includes properly, I know that is the issue since I was able to refine it to that point, but I'm not sure how to fix it.
In this super stripped down version of my code I have three .h files "Space.h" which is an abstract/virtual class which has to be inherited by a variety of different spaces that can appear on a typical Monopoly board: properties, jail, taxes, Chance, Community Chest, etc. The function that has to be inherited is run(Player&) which is what is "run" when you land on that particular space on the board, all functions that use run use a player passed by argument.
#pragma once
#include <string>
#include "Player.h"
class Space
{
public:
virtual void run(Player&) = 0;
};
My second .h file is the "Property.h" this inherits from Space
#pragma once
#include "Space.h"
class Property : Space
{
public:
void run(Player&) override;
int i{ 0 };
};
Lastly I have the "Player.h" which has two variables a name and a vector of properties it owns.
#pragma once
#include <string>
#include <vector>
#include "Property.h"
class Player
{
public:
std::string name{ "foo" };
void addProperty(Property p);
private:
std::vector <Property> ownedProperties;
};
Here's a very basic Property implementation
#include "Property.h"
#include <iostream>
void Property::run(Player & p)
{
std::cout << p.name;
}
Player implementation
#include "Player.h"
#include <iostream>
void Player::addProperty(Property p)
{
ownedProperties.push_back(p);
}
And finally main
#include "Player.h"
#include "Space.h"
#include "Property.h"
int main()
{
Player p{};
Property prop{};
prop.run(p);
system("pause");
}
Every time this is run I get a slew of errors, I'm sure it's got to do something with the circular include logic, with player including property, and property including space, which includes player. But, I don't see a workaround considering #include is needed to know how everything is defined isn't? Or are these errors referring to something else?
You have a circular include problem. Player includes Property which includes Space which includes Player again.
You can break the circle by not including Player.h in Space.h and only forward declare the class
#pragma once
class Player;
class Space
{
public:
virtual void run(Player&) = 0;
};
Aaand im back again with my second question and im kinda not sure about wether i should have posted all the seperate classes cuz it looks somewhat long. And im sure the solution is pretty small.
Anyways, i am at polymorphism tutorial vid that i am following and everything works fine if i follow it and put all classes in "main.cpp". But when i tried to do the same program with seperate classes (seen below) i am getting error "
E:\Codeblocks\Poly\main.cpp|11|error: cannot convert 'Ninja' to 'Enemy*' in initialization|".*
I kinda understand what the error is saying..i think.. but dont know what i did wrong since the same code was working when Enemy and Ninja class wasnt seperate but now as seperate classes its not working. I think i included those classes properly in main.cpp.
main.cpp
#include <iostream>
#include "Enemy.h"
#include "Ninja.h"
#include "Monster.h"
int main()
{
Ninja n;
Monster m;
Enemy *enemy1=&n;
Enemy *enemy2=&m;
enemy1->setAttackPower(20);
enemy2->setAttackPower(50);
n.attack();
m.attack();
return 0;
}
Enemy.h
#ifndef ENEMY_H
#define ENEMY_H
class Enemy
{
public:
Enemy();
void setAttackPower(int a);
protected:
int attackPower;
private:
};
#endif // ENEMY_H
Enemy.cpp
#include "Enemy.h"
Enemy::Enemy()
{
//ctor
}
void Enemy::setAttackPower(int a)
{
attackPower=a;
};
Ninja.h
#ifndef NINJA_H
#define NINJA_H
class Ninja
{
public:
Ninja();
void attack();
protected:
private:
};
#endif // NINJA_H
Ninja.cpp
#include "Ninja.h"
#include <iostream>
Ninja::Ninja()
{
//ctor
}
void Ninja::attack(){
std::cout<<" I am a ninja. Ninja chop! -"<<attackPower<<"\n";}
This is because your Ninja class is not inhereted from Enemy class. You must define Ninja class like this:
#include "Enemy.h"
class Ninja : public Enemy
{
public:
Ninja();
void attack();
protected:
private:
};
EDIT: I added #include directive. Without it compiler won't know, where to find Enemy class declaration.
Alright, so I have two classes, Vending and Payment. Payment is the child of Vending. I keep getting the "base class undefined" error in my code.
Here are the two header files:
//Parent class (Vending.h)
#ifndef VENDING_H
#define VENDING_H
#include "Main.h";
namespace Vending
{
class Vending
{
public:
Vending();
Vending(int);
void setRequiredAmount(int);
int getRequiredAmount();
protected:
int selectedItem;
int requiredAmount;
};
}
#endif VENDING_H
//child class (Payment.h)
#ifndef PAYMENT_H
#define PAYMENT_H
#include "Vending.h"
namespace Vending
{
class Payment : public Vending
{
public:
Payment(int);
int getEnteredAmount();
void setEnteredAmount(int);
protected:
int enteredAmount;
};
}
#endif PAYMENT_H
It would be greatly appreciated if I can get some help to resolve this error
You say Main.h includes Payment.h, which DOES lead to circular dependencies. Read this post for additional information: http://forums.codeguru.com/showthread.php?288147-C2504-Base-class-undefined-(other-posts-have-no-solution)&p=919112#post919112
You need to rethink your project properly, conditions like this should not happen. Simply try to remove the #include "Main.h" from the Vending.h, and compile Payment.cpp...
I am trying to implement a player class, so I created two files in my threads folder,
player.cc and player.h
player.h goes like this :
#ifndef PLAYER_H
#define PLAYER_H
#include "utility.h"
class Player()
{
public:
//getPlayerID();
};
#endif
then player.cc goes like
#include "player.h"
class Player()
{
string playerID;
int timeCycle;
}
Then in my main.cc and threadtest.cc , I add in #include player.h and then I start to errors and it fails to compile. I am new to nachos and a little bit unfamiliar with c++, so I am confused as to how to resolve this problem. Nachos does not provide a solution through the compiler either.
When I type gmake, it says two things for errors.
1. parse error before '(' in player.h (referring to Player())
2. * [main.o] Error 1
Let's go through line-by-line:
#ifndef PLAYER_H
#define PLAYER_H
#include "utility.h"
So far so good, you might check if your compiler supports #pragma once, but the macro will work perfectly fine.
class Player()
() aren't allowed in a class name, take them off
{
public:
//getPlayerID();
};
#endif
The rest of the header file is ok. Let's look at the implementation file:
#include "player.h"
Perfect. Putting a class in a header is the best way to make sure you only have one definition used in your whole program.
class Player()
Parentheses aren't allowed, but here you have a bigger problem. You already have a class with that name. Let the header provide the class definition, the implementation file just needs to provide the non-inline member functions (and any helper code).
{
string playerID;
int timeCycle;
}
Here's a complete corrected version:
#if !defined(PLAYER_H)
#define PLAYER_H
#include <string>
#include "utility.h"
class Player
{
std::string player_id;
int time_cycle;
public:
// this is how you make a constructor, the parenthesis belong here, not on the class name
Player(std::string id, int time);
std::string getPlayerId() const;
};
#endif /* !defined(PLAYER_H) */
and implementation file
#include "player.h"
// and this is how you write a non-inline constructor
Player::Player(std::string id, int time)
: player_id(id)
, time_cycle(time)
{}
std::string Player::getPlayerId() const
{
return player_id;
}
All of these problems are really basic C++ stuff, nothing to do with NachOS.
Did you modify the Makefile.common in the root nachos directory? I think you should add some value to THREAD_H, THREAD_O and THREAD_C.