I am relatively new to c++ and am having a heck of a time getting my main program to instantiate my class. I am used to java so I'm not sure if I am mixing up the two languages as I attempt to do this and that is my problem or maybe I just don't understand the concept correctly.
The object of my program: The object of this program is to create a template class from an interface that will make a sorted array that you can add and remove items from it while keeping it sorted.
Note: Please help me actually understand this process as to just telling me the exact code to use because I really want to understand what I am doing wrong for next time.
Step 1: I created my sorted interface:
sortedInterface.h
#ifndef _SORTED_INTERFACE
#define _SORTED_INTERFACE
#include <vector>
using namespace std;
template<class ListItemType>
class sortedInterface
{
public:
virtual bool sortedIsEmpty();
virtual int sortedGetLength();
virtual bool sortedInsert(ListItemType newItem);
virtual bool sortedRemove(ListItemType anItem);
virtual bool sortedRetrieve(int index, ListItemType dataItem);
virtual int locatePosition(ListItemType anItem);
}; // end SortedInterface
#endif
then I used the interface to create the sorted.h file:
sorted.h
#include "sortedInterface.h"
#include <iostream>
#ifndef SORTED_H
#define SORTED_H
using namespace std;
template<class ListItemType>
class sorted
{
public:
sorted();
sorted(int i);
bool sortedIsEmpty();
int sortedGetLength();
bool sortedInsert(ListItemType newItem);
bool sortedRemove(ListItemType anItem);
bool sortedRetrieve(int index, ListItemType dataItem);
int locatePosition(ListItemType anItem);
protected:
private:
const int DEFAULT_BAG_SIZE = 10;
ListItemType items[];
int itemCount;
int maxItems;
};
#endif // SORTED_H
and finally I created the sorted.cpp (I only included the constructor for now as I can't even get that working)
#include "sorted.h"
#include <iostream>
using namespace std;
template<class ListItemType>
sorted<ListItemType>::sorted()
{
itemCount = 0;
items[DEFAULT_BAG_SIZE];
maxItems = DEFAULT_BAG_SIZE;
}
My main program:
#include "sortedInterface.h"
#include "sorted.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
sorted<string> sorted1 = new sorted();
return 0;
};
Any help is appreciated in explaining where my logic is failing on this and any hints on how to properly execute my task. Thanks!
1) operator "new" returns a pointer, not an object.
sorted<string>* sorted1 = new sorted<string>();
2) However, in your small example, there is no need to create sorted1 using "new".
sorted<string> sorted1;
One word of advice -- Java is not C++. You made the two mistakes that many first-time Java programmers make when writing C++ code, namely 1) believing that to create an object, you must use "new", and 2), that "new" returns a reference.
There are a few things wrong with your interface/implementation. A class template is usually implemented entirely in the header in which it's declared; this is because the compiler creates a whole new type for each type you use with your template.
Second, in your sortedInterface template, you've made the members virtual which still requires a definition, but you do not supply one. You can mark your member functions with = 0; to make them all pure virtual, which means the classes that inherit your sortedInterface will have to implement those members instead.
Third, as PaulMcKenzie pointed out, operator new() returns a pointer to a heap-allocated object, but you're expecting a value type.
Finally, please take a look at smart pointers if you're using naked new()s everywhere.
I notice the following additional anomalies in the entire implementation:
An interface is something which should be non-instantiable but it is
instantiable in your case (because there is not even a single pure
virtual function in your so called interface) Standard rule is to
make all the functions in the interface pure virtual (=0)
class Sorted does not inherit from the so-called interface
sortedInterface
You have not defined all versions of your constructor in your class
Sorted
If you want the polymorphism to work (Interface to Concrete), you
need to have virtual class destructors in both the interface and
concrete class
Related
First of all, I would like to apologize if I used incorrect terminology in the question. I do not have any sort of formal training in programming. It was the best I could do to convey the problem.
My question is this:
In the following code structure, how can the Inventory class have complete access to Items vector inside the Player class WITHOUT making the vector static?
-- main.cpp
#include <iostream>
#include <vector>
#include "World.hpp"
#include "Interface.hpp"
int main()
{
World objWorld;
Interface objInterface;
return 0;
}
-- World.hpp
#pragma once
#include "Player.hpp"
class World
{
public:
Player objPlayer;
};
-- Player.hpp
#pragma once
class Player
{
public:
std::vector<int> Items;
};
-- Interface.hpp
#pragma once
#include "Inventory.hpp"
class Interface
{
public:
Inventory objInventory;
};
-- Inventory.hpp
#pragma once
class Inventory
{
public:
// Needs to have complete access to Items, be able to see and modify the vector
};
This is not a C++ question, this is Object Oriented Programming question.
There are many ways to do this. But all of them involve more than one object working together. Either the Player has to have a reference (pointer) to Inventory, or the Inventory has to have a reference to player - somehow.
Here are some options:
You can pass a pointer in constructor (this is just a quick example, please use shared pointers)
class Inventory
{
private:
Player *owner;
public:
Inventory(Player *owner) : owner(owner){}
};
Pass it as method argument
class Inventory
{
public:
void drawFor(Player *owner);
};
Set a field value.
class Inventory
{
private:
Player *owner;
public:
void setOwner(Player *owner) {this->owner = owner;}
};
As a side note, are you sure that Player has vector of items? I would venture that Player may OWN an Inventory. Inventory is more than just a vector of items. It has (potentially complex) limitations on number of items, it can maintain weight of items that affects player's movement, it can be expanded by adding containers. All of it can be useful to Player or NPC. You just have to come up with a good interface for Inventory
There are several issues which you have to consider.
access rights. From outside a class (i.e. from any code other than the class's member functions etc) only public members are accessible, except for friends, which have full access.
visibility. In order to use a member, you must see its declaration.
Thus, you should
// Inventory.hpp
#pragma once
#include "World.hpp" // makes class World visible
class Inventory
{
World& objWorld; // reference to 'my' world object
public:
Inventory(World& w) : objWorld(w) {}
void foo()
{
std::sort(objWorld.objPlayer.Items.begin(),
objWorld.objPlayer.Items.end());
}
};
Of course, you must adapt the rest of your code accordingly:
// Interface.hpp
#pragma once
#include "Inventory.hpp"
class Interface
{
Inventory objInventory;
public:
Interface(World& w) : objInventory(w) {}
};
and
// main.cpp
#include "Interface.hpp"
int main()
{
World objWorld;
Interface objInterface(objWorld);
return 0;
}
Class members can be accessed using the member access operator . (period character). The left hand side is (an expression that yields) an instance of the class, and the right hand side is the name of the member.
Let p be an instance of Player. The expression p.Items will yield the vector of that instance. The class has to be defined, before its members can be accessed.
I just finished creating my binary tree class only to realise that I was supposed to make it as a template. I've spent hours now trying to get to convert it to a template, but I keep getting a multitude of errors ranging from "invalid use of template-name" to "extra qualification of a member". I am new to the concept of templates but I have an idea of what I'm trying to achieve.
BTree.cpp
#include <iostream>
#include <string>
#include "BTree.h"
using namespace std;
BTree::BTree(board startboard, string startplayer)
{
treeboard = startboard;
player = startplayer;
root = new BTNode(treeboard, player,-1,-1);
}
BTree::~BTree()
{
delete root;
}
int BTree::sumtree()
{
if (root->getvalue(-1) > root->getvalue(1))
return root->getchildposition(-1);
else
return root->getchildposition(1);
}
BTree.h
#include <string>
#include "BTNode.h"
#include "board.h"
using namespace std;
class BTree
{
public:
BTree(board startboard, string startplayer);
~BTree();
int sumtree();
private:
string player;
board treeboard;
BTNode *root;
};
'startplayer' is currently a string, I would like this to be the generic template type.
What should my process be for turning this into a single template file?
Well, let's first look what errors or other deficits your code has:
Your BTree has a custom dtor, because it holds resources. But you are violating the rule-of-3:
You need to define or delete, at minimum, your assignment-operator and copy-ctor.
As an alternative (preferable), change BTNode *root; to use std::unique_ptr.
The first thing included in the implementation-file should always be its own header, to find broken dependencies in the header.
The header should include everything neccessary to use it, and not one bit more.
Now, there are good reasons why templates are usually header-only:
The compiler needs the definition to instantiate it.
Use the opportunity to move some of the functions into the class.
Next, you define a template like this:
template<class T> class BTree {
int BTree::sumtree();
};
And non-inline members like this:
template<class T> int BTree<T>::sumtree() {
return //...
}
In the template, you can use the type-argument like a normal type.
A note on BTNode: It's an implementation-detail of BTree, so put its definition into the class (which makes templating it the same and using it easier as well.)
Alternatively, if you don't actually need all the template-arguments for BTNode as well (or want to share its implementation), template it separately.
Don't forget to change all references from BTree though.
First of all to use templates in C++ all of your executable code NEEDS to be in the .h file so it is available at compile time.
Then to template your class, the usual way is to make it like :
template<class T>
class BTree
{
Btree(T startPlayer)
{
player = startPlayer;
}
// ... snip ...
T player;
}
I am working on a little game engine but I got stuck at something. Explanation : I have two classes, cEntity And ObjectFactory :
cEntity
class cEntity:public cEntityProperty
{
Vector2 position;
Vector2 scale;
public:
cEntity(void);
cEntity(const cEntity&);
~cEntity(void);
public:
void init();
void render();
void update();
void release();
};
ObjectFactory
#include "cEntity.h"
#include <vector>
class ObjectFactory
{
static std::vector<cEntity> *entityList;
static int i, j;
public:
static void addEntity(cEntity entity) {
entityList->push_back(entity);
}
private:
ObjectFactory(void);
~ObjectFactory(void);
};
std::vector<cEntity> *ObjectFactory::entityList = new std::vector<cEntity>();
Now I am adding new cEnity to ObjectFactory in cEntity constructor but facing an error related to circular references: for using ObjectFactor::addEntity() I need to define the ObjectFactory.h in cEntity class but it creates a circular reference.
I think your code might have an underlying architectural issue given how you have described the problem.
Your ObjectFactory should be handling the cEntities, which in turn should be unaware of the "level above". From the description of the problem you are having, it implies that you're not sure what class is in charge of what job.
Your cEntitys should expose an interface (i.e. all the stuff marked "public" in a class) that other bits of code interact with. Your ObjectFactory (which is a bit badly named if doing this job, but whatever) should in turn use that interface. The cEntitys shouldn't care who is using the interface: they have one job to do, and they do it. The ObjectFactory should have one job to do that requires it to keep a list of cEntitys around. You don't edit std::string when you use it elsewhere: why is your class any different?
That being said, there's two parts to resolving circular dependencies (beyond "Don't create code that has circular dependencies in the first place" - see the first part to this answer. That's the best way to avoid this sort of problem in my opinion)
1) Include guards. Do something like this to each header (.h) file:
#ifndef CENTITY_H
#define CENTITY_H
class cEntity:public cEntityProperty
{
Vector2 position;
Vector2 scale;
public:
cEntity(void);
cEntity(const cEntity&);
~cEntity(void);
public:
void init();
void render();
void update();
void release();
};
#endif
What this does:
The first time your file is included, CENTITY_H is not defined. The ifndef macro is thus true, and moves to the next line (defining CENTITY_H), before it moves onto the rest of your header.
The second time (and all future times), CENTITY_H is defined, so the ifndef macro skips straight to the endif, skipping your header. Subsequently, your header code only ever ends up in your compiled program once. If you want more details, try looking up how the Linker process.
2) Forward-declaration of your classes.
If ClassA needs a member of type ClassB, and ClassB needs a member of type ClassA you have a problem: neither class knows how much memory it needs to be allocated because it's dependant on another class containing itself.
The solution is that you have a pointer to the other class. Pointers are a fixed and known size by the compiler, so we don't have a problem. We do, however, need to tell the compiler to not worry too much if it runs into a symbol (class name) that we haven't previously defined yet, so we just add class Whatever; before we start using it.
In your case, change cEntity instances to pointers, and forward-declare the class at the start. You are now able to freely use ObjectFactory in cEntity.
#include "cEntity.h"
#include <vector>
class cEntity; // Compiler knows that we'll totally define this later, if we haven't already
class ObjectFactory
{
static std::vector<cEntity*> *entityList; // vector of pointers
static int i, j;
public:
static void addEntity(cEntity* entity) {
entityList->push_back(entity);
}
// Equally valid would be:
// static void addEntity(cEntity entity) {
// entityList->push_back(&entity);}
// (in both cases, you're pushing an address onto the vector.)
// Function arguments don't matter when the class is trying to work out how big it is in memory
private:
ObjectFactory(void);
~ObjectFactory(void);
};
std::vector<cEntity*> *ObjectFactory::entityList = new std::vector<cEntity*>();
i wrote this code but friend function is not working(foodmoney and hobbymoney are not declare in my friend function. where is my Error here ?
#include <iostream>
using namespace std;
class myBase
{
private:
int friendvar;
int foodmoney;
int hobbymoney;
public:
void setdata();
myBase(){friendvar=0;}
friend void caldata(myBase &mbo);
};
void myBase::setdata()
{
cout<<"Enter foodmoney :" ;cin>>foodmoney;
cout<<"enter hoobymoney:";cin>>hobbymoney;
}
void caldata(myBase &mbo)
{
mbo.friendvar=(foodmoney+hobbymoney)/2;
cout<<mbo.friendvar<<endl;
}
int main()
{
myBase baseobj;
baseobj.setdata();
myBase friends;
caldata(friends);
return 0;
}
mbo.friendvar=(foodmoney+hobbymoney);
should be
mbo.friendvar=(mbo.foodmoney+mbo.hobbymoney);
etc. etc.
Friend functions are not member functions, so they do not have special access to any particular object. You must specify which object you wish to access (by using mbo in your case).
Having said that I can't see any good reason why caldata is a friend function. Why not make it a regular member function? Or maybe you should make it a friend function with two arguments? It's hard to say what you're trying to achieve here.
change
cin>>foodmoney;
to
cin>>mbo.foodmoney;
and change
cin>>hobbymoney;
to
cin>>mbo.hobbymoney;
Your code doesn't compile at all. Fix is described already. But to make ti complete:
As you have referenced friendvar using mbo.friendvar, do the same for foodmoney and hobbymoney.
Also you have not initialized foodmoney and hobbymoney in your constructor. And in your call to caldata(friends); you are therefor getting random result printed on screen.
Last: you instantiate new object with myBase friends; so this is completely new object that is not affected by previous call of setdata().
Your low level requirements for this function are not defined in your question, I cannot help more.
I'm writing some Arduino code and attempting to use inheritance in some classes. I have a class "Actor" (my base class) and a class "Marble" (which inherits from Actor). Here are the header files:
Actor.h:
#ifndef Actor_h
#define Actor_h
#include "Arduino.h"
class Actor
{
public:
Actor();
void speak();
private:
};
#endif
Marble.h:
#ifndef Marble_h
#define Marble_h
#include "Arduino.h"
#include "Actor.h"
class Marble : public Actor {
public:
Marble();
virtual void speak();
private:
};
#endif
Actor.cpp:
#include "Arduino.h"
#include "Actor.h"
Actor::Actor()
{
}
void Actor::speak() {
Serial.println("Actor");
}
Marble.cpp:
#include "Arduino.h"
#include "Marble.h"
void Marble::speak() {
Serial.println("Marble");
}
And finally, in the loop function I do:
void loop() {
Marble marble;
Actor children[2];
children[0] = marble;
children[0].speak();
Which results in "Actor" being printed.
I discovered this nice link which seems similar to my issue, but the resolution does not seem to work for me:
http://arduino.cc/forum/index.php?topic=41884.0
So. It seems like when I create my array of "Actors" and try and stick Marble in there it gets cast to an Actor, or something like that. Problem is, I'll have a few different characters that will all inherit from "Actor" and I'd like an array of them to iterate over and call overridden methods on them.
So, perhaps the problem is how I'm approaching this problem, or maybe there's some syntax errors? I don't know!
Thanks for your help,
Kevin
You need to declare speak as virtual in the Actor class, not just in the Marble class; without that, Actor::speak is a non-virtual function, so you will always be called in preference to the virtual Marble::speak.
For what it's worth, this has nothing to do with the Arduino: it's just a straight C++ issue.
Your problem is that children is an array of type Actor. The line children[0] = marble is taking a Marble object, converting it to an Actor object and copying the results to children[0]. Since the call to children[0].speak() is on an Actor, you get the Actor version.
In order for this to work the way you want, you need to copy a pointer or reference to the object rather than the object itself. That is, you want something like `Actor* children[2]':
Marble marble;
Actor* children[2];
children[0] = &marble;
children[0]->speak();
Of course if children has scope outside of loop, this will fail utterly and you'll need to use new to create your marbles.
Better yet, assuming Arduino has the STL, you should use vector and shared_ptr or something similar.
[Update] As Philip notes, this will also require that the speak method in Actor be declared virtual.