rogue like game initializing error - c++

I'm making a simple map for simple rogue-like game.
So I need to initialize map with Objects created for each array cell by receiving data from character array[i][j].
Suggested that such CWall, CDoor classes are defined in other files like CWall.cpp, CWall.h, Underneath are the code to initialize in map.cpp
But is this right way to code?
I think this causes a problem of allocating memory.
CObject CMap::insertObject(char character){
if (character = '*') {
CWall cwall;
return cwall;
}
if (character = 'D') {
CDoor cdoor;
return cdoor;
}
if (character = 'F') {
CFood cfood;
return cfood;
}
if (character = 'K') {
CKey ckey;
return ckey;
}
if (character = 'M') {
CMMonster cmmonster;
return cmmonster;
}
if (character = 'm') {
CMonster cmonster;
return cmonster;
}
if (character = '#') {
CPlayer cplayer;
return cplayer;
}
if (character = 'P') {
CPrincess cprincess;
return cprincess;
}
if (character = '&') {
CRock crock;
return crock;
}
if (character = 'S') {
CShield cshield
return cshield;
}
else {
CShield cshield;
return cshield;
}
}
void CMap::initialize(char arr[][COLS]){
for (int i = 0; i <= 11; i++){
for (int j = 0; j <= 38; j++){
char character = arr[i][j];
insertObject(character);
}
}
}

That's not the right way to do it. You are subject to object slicing, since my guess is that your CObject is an object and not a pointer to some object. You need to either return a pointer of type CObject* in your function, then for each case return a new CMonster or new CPlayer etc. Even better, use a smart pointer instead.
What you are trying to implement is called a factory method pattern, see e.g. How to implement the factory method pattern in C++ correctly for more details.

While others correctly pointed out how to code the idea you want coded, I will focus on another thing. Namely, improper usage of polymorphism here. Inheriting everything from meaningless Object smells like Java, and is not welcome in C++. There is simply nothing in common between Princess and Monster (one is kissed, another one is slayed, and to do what with which is up to one's taste), so when both are inherited from Object, it is extremely hard to program the proper game mechanic. You will have to store the actual object type as well (say, an enumeration), and than cast to this type - because only one of them will have method kiss() on them!
The whole code will be a spaghetti of unsafe casts and will be impossible to maintain or reason about.
Instead, go for stongly typed approach. Always know what type is in front of you!

You should be dealing with the data dynamically. What you're doing now has several problems.
A better approach would be:
CObject* CMap::insertObject(char character){
if (character = '*') {
return new CWall();
}
...
This will utilize polymorphism to hide the actual class (such as CWall) behind the generic interface (CObject). As you wrote it, each "new" object, such as cdoor, would actually be passed to a copy constructor for CObject. None of which actually accomplished anything meaningful.
Of course, you need to pair these creations with proper destructions down the road.

Well, for one thing, you aren't actually initializing anything. CWall* cwall = new CWall; would be the proper way to dynamically allocate and initialize a new CWall object (assuming CWall has a default constructor, of course), or any object for that matter.
What you also need to bear in mind is that, for everything you allocate with new, you have to deallocate with delete later. Thus, you will need to put some thought into how you store those allocated objects, so you can ensure your destructor or cleanup function removes all of them when you're done. One design pattern to consider would be the Object Pool, though there are easily several dozen good ways to do it. That's footwork you're going to have to do yourself, though, as only you know enough about your project to select the right design pattern. (That book I linked to is a great resource.)
EDIT: As per your comment, there is one other issue, and that is that you are returning different types of objects. This is a simple issue of inheritance - as long as all of those objects inherit from an abstract base class of CObject (or something similar), you can simply list the return type as CObject*. Then, as long as you're returning an object (or a pointer to an object) that inherits from CObject, you're golden.
EDIT 2: Whenever you use new, you are actually getting a pointer to the dynamically allocated object. That creates some problems of its own, including that new can return a null pointer if the allocation fails. Be sure to check for that! A smart pointer can prevent many of those problems, but your use of smart pointers depends on your design pattern choices.

Related

C++, A way to update Pointers after vector resize, and erase vector objects without copying?

I believe this will be my first question for the site, so I apologize for any mistakes or errors in this post. I am a beginner C++ programmer as well, so forgive me if my questions come across as “noobish”.
Background: A collection of Parent Entity objects are created at startup (and currently not removed or added-to during runtime), and are then linked to a series of Activator Entity objects (both at the beginning, and during, runtime) through a Child Entity object. When establishing a link, the Parent generates a Child (which is stored in a local vector), and returns a pointer to the Child for the Activator to store.
Activators will “activate” children they are linked with, which will then do jobs based off internal and Parent settings. After being activated, they are also updated periodically by the Parent, continuing until eventually deactivating.
Below is a simplified example of the classes present.
class ParentEntity {
std::vector<ChildEntity> m_Children;
std::vector<ChildEntity*> m_ActiveChildren;
public:
//Funcs
ParentEntity(unsigned expectedChildren) { m_Children.reserve(expectedChildren); }
ChildEntity* AddChild(){
m_Children.push_back(ChildEntity(*this));
return &(m_Children.back());
}
void RemoveChild(unsigned iterator) {
//Can't figure a way to remove from the m_Children list without disrupting all pointers.
//m_Children.erase(m_Children.begin() + iterator); Uses Copy operators, which wont work as Const values will be present in Child
}
void AddActiveChild(ChildEntity* activeChild) {
m_ActiveChildren.push_back(activeChild);
}
bool Update(){ //Checks if Children are active,
if (!m_ActiveChildren.empty()) {
std::vector<ChildEntity*> TempActive;
TempActive.reserve(m_ActiveChildren.size());
for (unsigned i = 0; i < m_ActiveChildren.size(); i++) {
if (m_ActiveChildren[i]->Update()) {
TempActive.push_back(m_ActiveChildren[i]);
}
}
if (!TempActive.empty()) {
m_ActiveChildren = TempActive;
return true;
}
else {
m_ActiveChildren.clear();
return false;
}
}
else {
return false;
}
}
};
class ChildEntity {
public:
ChildEntity(ParentEntity& Origin) //Not const because it will call Origin functions that alter the parent
:
m_Origin(Origin)
{}
void SetActive() {
m_ChildActive = true;
m_Origin.AddActiveChild(this);
}
bool Update() { //Psuedo job which causes state switch
srand(unsigned(time(NULL)));
if ((rand() % 10 + 1) > 5) {
m_ChildActive = false;
}
return m_ChildActive;
}
private:
ParentEntity& m_Origin;
bool m_ChildActive = false;
};
class ActivatorEntity {
std::vector<ChildEntity*> ActivationTargets;
public:
ActivatorEntity(unsigned expectedTargets) { ActivationTargets.reserve(expectedTargets); }
void AddTarget(ParentEntity& Target) {
ActivationTargets.push_back(Target.AddChild());
}
void RemoveTarget(unsigned iterator) {
ActivationTargets.erase(ActivationTargets.begin() + iterator);
}
void Activate(){
for (unsigned i = 0; i < ActivationTargets.size(); i++) {
ActivationTargets[i]->SetActive();
}
}
};
With that all laid out, my three questions are:
Is there a way to update Pointers when a vector resizes?
When a Child is added, if it goes past the expected capacity, the vector creates a new array and moves the original objects to the new location. This breaks all of the Activator pointers, and any m_ActiveChild pointers, as they are pointing to the old location.
Is there a way to remove Child objects from the m_Children vector?
Since ChildEntity objects will host const items within them, copy assignment operations won’t work smoothly, and the Vector’s erase function won’t work. The m_Children vector could be rebuilt without the unwanted object through a temporary vector and copy constructor, but this leads to all of the pointers being wrong again.
Please let me know if there are any other suggested optimizations or corrections I should make!
Thank you all for your help!
Your problem, abstractly seen, is that on one hand you have collections of objects that you want to iterate through, kept in a container; and that on the other hand these objects are linked to each other. Re-ordering the container destroys the links.
Any problem can be solved by an additional indirection: Putting not the objects but object handles in the container would make re-ordering possible without affecting cross-references. The trivial case would be to simply use pointers; modern C++ would use smart pointers.
The disadvantage here is that you'll move to dynamic allocation which usually destroys locality right away (though potentially not if most allocations happen during initialization) and carries the usual run-time overhead. The latter may be prohibitive for simple, short-lived objects.
The advantage is that handling pointers enables you to make your objects polymorphic which is a good thing for "activators" and collections of "children" performing "updates": What you have here is the description of an interface which is typically implemented by various concrete classes. Putting objects in a container instead of pointers prevents such a design because all objects in a container must have the same concrete type.
If you need to store more information you can write your own handle class encapsulating a smart pointer; perhaps that's a good idea from the beginning because it is easily extensible without affecting all client code with only a moderate overhead (both in development and run time).

Polymorphism vs DownCasting

Let's say I have a Base class Employee and an derived class Manager, like below:
class Employee
{
public:
string Name;
};
class Manager : public Employee
{
public:
string Designation;
};
While implementing some function like below:
Employee* SomeFunction(bool SomeCondition)
{
Employee *Emp = NULL;
if (SomeCondition)
{
//Code goes here : Both Implementation 1 and 2 work fine!
}
return Emp;
}
When SomeCondition is true, I want to return a non-null object of type Manager. In such a scenario, both below pieces of code seem to fit the bill:
Implementation 1:
Manager *Mng = new Manager;
Mng->Name = "Adam";
Mng->Designation = "BOSS";
Emp = Mng;
Implementation 2:
Emp = new Manager;
Manager *Mng = (Manager*)Emp;
Mng->Name = "Adam";
Mng->Designation = "BOSS";
Since both work just fine, I would like to know which one among the two is the more efficient one?
Which one is using the concept of Polymorphism?
Is the type casting in Implementation 2 a down-cast? Is it good practice?
While I see some reasons behind your questions, I think you
need to improve the your example
you are saying that you need to return a non-null object
of type "Manager", while your define "SomeFunction(bool SomeCondition)"
to return "Employee".
if you are indeed going to return "Employee" object why bothering
initializing "Designation" while you will not be able to access it
later. For example:
cout << SomeFunction(true)->Designation(); // error !
So, I'm not sure what do mean by saying your examples work fine,
since the context is not clear.
** Comparing Implementation 1 and 2 / About dynamic casting
While both examples can improve, I think Implementation 1 is slightly
better. In both cases you do dynamic casting. However, in Implementation
1, you do an implicit upcasting in "Emp = Mng;", while in Implementation 2
you do downcasting in "Manager Mng = (Manager)Emp;".
In general you should avoid casting (especially the downcasting since it's
not that safe all the time compared with upcasting), and if you have to
you should use C++ style casting (e.g. dynamic_cast). See the
example in
https://www.tutorialcup.com/cplusplus/upcasting-downcasting.htm
A better solution is to use virtual functions in order to avoid
casting and make room to add more objects types beside "Manager".
For example, your header may look like:
class Employee
{
public:
virtual void setDesignation(const string & d) = 0;
virtual string getDesignation() = 0;
};
class Manager : public Employee
{
public:
virtual void setDesignation (const string & d) {Designation=d;}
virtual string getDesignation() {return Designation;}
private:
string Designation;
};
and your function may look like:
Employee* SomeFunction(bool SomeCondition)
{
Employee *Emp = NULL;
if (SomeCondition)
{
Emp = new Manager;;
Emp->setDesignation("BOSS");
}
return Emp;
}
then if you want to access the Designation later, you can do
cout << SomeFunction(true)->getDesignation();
** About Polymorphism
you don't use any Polymorphism in both examples. This is becuase you don't
use any function that is type-specific, and so your runtime behaviour doesn't
vary depending on the "Employee" object (you are merely using one object type
"Manager" anyways !). See the example in
http://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm
Both of your implementations do what you want them to, however the second one is very bad practice.
First, let's clear up a misconception you seem to have: In your second implementation, you're not doing what is usually considered a downcast. You're using a C-style cast (see http://en.cppreference.com/w/cpp/language/explicit_cast), which will, among casting away things such as const, happily cast any pointer to a Manager*. For example, you might just as well do
Manager *Mng = (Manager*) new Employee; // not a good idea
or even
Manager *Mng = (Manager*) new int; // now, this is really bad...
As a general rule, you should never use C-style casts in C++.
You can do a safe downcast in C++ by using dynamic_cast:
Manager *Mng = dynamic_cast<Manager*>(ptr_to_manager); // will return a pointer to the Manager object
Manager *Mng = dynamic_cast<Manager*>(ptr_to_employee); // will return nullptr
Still, there is runtime overhead needed to check whether your cast is actually safe (ie, distinguish the first case in the example from the second). The need for a downcast is, by the way, usually an indication of bad design.
In short, the first implementation is the easier and obvious way to go: no need for an downcast, safe or unsafe.

Alternatives to an Object Pool?

I'm not quite sure that I need an object pool, yet it seems the most viable solution, but has some un-wanted cons associated with it. I am making a game, where entities are stored within an object pool. These entities are not allocated directly with new, instead a std::deque handles the memory for them.
This is what my object pool more or less looks like:
struct Pool
{
Pool()
: _pool(DEFAULT_SIZE)
{}
Entity* create()
{
if(!_destroyedEntitiesIndicies.empty())
{
_nextIndex = _destroyedEntitiesIndicies.front();
_destroyedEntitiesIndicies.pop();
}
Entity* entity = &_pool[_nextIndex];
entity->id = _nextIndex;
return entity;
}
void destroy(Entity* x)
{
_destroyedEntitiesIndicies.emplace(x->id);
x->id = 0;
}
private:
std::deque<Entity> _pool;
std::queue<int> _destroyedEntitiesIndicies;
int _nextIndex = 0;
};
If I destroy an entity, it's ID will be added to the _destroyedEntitiesIndicies queue, which will make it so that the ID will be re-used, and lastly it's ID will be set to 0. Now the only pitfall to this is, if I destroy an entity and then immediately create a new one, the Entity that was previously destroyed will be updated to be the same entity that was just created.
i.e.
Entity* object1 = pool.create(); // create an object
pool.destroy(object1); // destroy it
Entity* object2 = pool.create(); // create another object
// now object1 will be the same as object2
std::cout << (object1 == object2) << '\n'; // this will print out 1
This doesn't seem right to me. How do I avoid this? Obviously the above will probably not happen (as I'll delay object destruction until the next frame). But this may cause some disturbance whilst saving entity states to a file, or something along those lines.
EDIT:
Let's say I did NULL entities to destroy them. What if I was able to get an Entity from the pool, or store a copy of a pointer to the actual entity? How would I NULL all the other duplicate entities when destroyed?
i.e.
Pool pool;
Entity* entity = pool.create();
Entity* theSameEntity = pool.get(entity->getId());
pool.destroy(entity);
// now entity == nullptr, but theSameEntity still points to the original entity
If you want an Entity instance only to be reachable via create, you will have to hide the get function (which did not exist in your original code anyway :) ).
I think adding this kind of security to your game is quite a bit of an overkill but if you really need a mechanism to control access to certain parts in memory, I would consider returning something like a handle or a weak pointer instead of a raw pointer. This weak pointer would contain an index on a vector/map (that you store somewhere unreachable to anything but that weak pointer), which in turn contains the actual Entity pointer, and a small hash value indicating whether the weak pointer is still valid or not.
Here's a bit of code so you see what I mean:
struct WeakEntityPtr; // Forward declaration.
struct WeakRefIndex { unsigned int m_index; unsigned int m_hash; }; // Small helper struct.
class Entity {
friend struct WeakEntityPtr;
private:
static std::vector< Entity* > s_weakTable( 100 );
static std::vector< char > s_hashTable( 100 );
static WeakRefIndex findFreeWeakRefIndex(); // find next free index and change the hash value in the hashTable at that index
struct WeakEntityPtr {
private:
WeakRefIndex m_refIndex;
public:
inline Entity* get() {
Entity* result = nullptr;
// Check if the weak pointer is still valid by comparing the hash values.
if ( m_refIndex.m_hash == Entity::s_hashTable[ m_refIndex.m_index ] )
{
result = WeakReferenced< T >::s_weakTable[ m_refIndex.m_index ];
}
return result;
}
}
This is not a complete example though (you will have to take care of proper (copy) constructors, assignment operations etc etc...) but it should give you the idea what I am talking about.
However, I want to stress that I still think a simple pool is sufficient for what you are trying to do in that context. You will have to make the rest of your code to play nicely with the entities so they don't reuse objects that they're not supposed to reuse, but I think that is easier done and can be maintained more clearly than the whole handle/weak pointer story above.
This question seems to have various parts. Let's see:
(...) If I destroy an entity and then immediately create a new one,
the Entity that was previously destroyed will be updated to be the
same entity that was just created. This doesn't seem right to me. How
do I avoid this?
You could modify this method:
void destroy(Entity* x)
{
_destroyedEntitiesIndicies.emplace(x->id);
x->id = 0;
}
To be:
void destroy(Entity *&x)
{
_destroyedEntitiesIndicies.emplace(x->id);
x->id = 0;
x = NULL;
}
This way, you will avoid the specific problem you are experiencing. However, it won't solve the whole problem, you can always have copies which are not going to be updated to NULL.
Another way is yo use auto_ptr<> (in C++'98, unique_ptr<> in C++-11), which guarantee that their inner pointer will be set to NULL when released. If you combine this with the overloading of operators new and delete in your Entity class (see below), you can have a quite powerful mechanism. There are some variations, such as shared_ptr<>, in the new version of the standard, C++-11, which can be also useful to you. Your specific example:
auto_ptr<Entity> object1( new Entity ); // calls pool.create()
object1.release(); // calls pool.destroy, if needed
auto_ptr<Entity> object2( new Entity ); // create another object
// now object1 will NOT be the same as object2
std::cout << (object1.get() == object2.get()) << '\n'; // this will print out 0
You have various possible sources of information, such as the cplusplus.com, wikipedia, and a very interesting article from Herb Shutter.
Alternatives to an Object Pool?
Object pools are created in order to avoid continuous memory manipulation, which is expensive, in those situations in which the maximum number of objects is known. There are not alternatives to an object pool that I can think of for your case, I think you are trying the correct design. However, If you have a lot of creations and destructions, maybe the best approach is not an object pool. It is impossible to say without experimenting, and measuring times.
About the implementation, there are various options.
In the first place, it is not clear whether you're experiencing performance advantages by avoiding memory allocation, since you are using _destroyedEntitiesIndicies (you are anyway potentially allocating memory each time you destroy an object). You'll have to experiment with your code if this is giving you enough performance gain in contrast to plain allocation. You can try to remove _destroyedEntitiesIndicies altogether, and try to find an empty slot only when you are running out of them (_nextIndice >= DEFAULT_SIZE ). Another thing to try is discard the memory wasted in those free slots and allocate another chunk (DEFAULT_SIZE) instead.
Again, it all depends of the real use you are experiencing. The only way to find out is experimenting and measuring.
Finally, remember that you can modify class Entity in order to transparently support the object pool or not. A benefit of this is that you can experiment whether it is a really better approach or not.
class Entity {
public:
// more things...
void * operator new(size_t size)
{
return pool.create();
}
void operator delete(void * entity)
{
}
private:
Pool pool;
};
Hope this helps.

Set of shared_ptr and set function count

I have a set of shared pointers.
I want to make a function that checks if a shared pointer exists in it.
I assumed I need to use set.count to get it.
But I get 0 all the time... even though the shared pointer exists in there.
So my question is: how does count compare shared pointers?
Please bare in mind I am new to C++, I can provide with code, but there's a lot of it.
EDIT 2:
The function that checks the building and adds a car.
void Garage::addCar(Car& n, Building& m){
shared_ptr<Building> mm(new Building(m));
if (this->Buildings.count(mm) == 0){
cout << m.name << " doesn't exist in " << this->name << "." << endl;
return;
}
shared_ptr<Car> s(new Car(n));
m.addCar(s);
Cars.insert(s);
}
Function that creates Buildings
Building Garage::create Building(string name){
shared_ptr< Building> f_ptr(new Building(name));
Buildings.insert(f_ptr);
return (*f_ptr);
}
Class garage
class Garage {
public:
Garage(string name);
~Garage();
void admitCar(Car& n, Building& m);
void dismissCar(Car& n, Building& m);
void employEmployee(Employee& n, Building& m);
void dismissEmployee(Employee& n, Building& m);
Building createBuilding(string name);
void deleteBuilding(Building&);
private:
int nextIndex;
string name;
set<shared_ptr<Building> > Buildings;
set<shared_ptr<Employee> > Employees;
set<shared_ptr<Car> > Car;
}
Whenever I want to add a car to a building, it says that that building doesnt exist in that garage...
SOLUTION(my own):
bool Garage::hasBuilding(shared_ptr<Building> f){
return (this->Buildings.count(f) != 0);
}
This is the function I created. It works.
I tried Jonathan Wakely and LiKao ways but they were a bit too complicated for me and I had problems which again I couldn't myself solve.
Thank You for the help :)
The pointers you are comparing are different, because they are pointing to different objects. Whenever you say new Building a new building will be created, although it my have the same name as an older building. Hence any pointer to that new Building will be different to any pointer to the old Building from which the new one was created. Hence the comparison is correct, the new Building is not present in the set (you just created it by copying so it cannot be present).
You want a set, which can be compared based on a property of the object the pointer points to. For this you need to add a different comparison function which looks into the pointer to the object. Something like this should work:
struct less_building : std::binary_function<std::shared_ptr<Building>,std::shared_ptr<Building>,bool> {
bool operator()( const std::shared_ptr<Building> & b1, const std::shared_ptr<Building> & b2 ) {
return std::less( b1->name, b2->name );
}
};
This may need some friends declaration depending on your definition of Building, but in general something like this will do the trick.
NOTE1:
Be sure to understand the implications of this, before you use this trick. Using this comparator will mean, that no two Buildings in your set can have the same name, irregardless of any other attribute they may have. Each pair of Buildings which have the same name will afterwards be considered the same Building. Depending on your modelling domain, this may or may not be what you want.
In case you want to also compare other attributes in case the names are the same, then you have to add this to your comparison functor. However then that means that there can be no two Buildings which have the same set of attributes. Again, this may or may not be what you want, depending on the problem.
NOTE2:
Usually it is very inconvenient, to mix std::shared_ptr and references to the same types of objects, which also leads to the problem you are experiences. If you are using std::shared_ptr for a type at any place, you should try to be consistent and only pass these std::shared_ptr around. The reason is, that converting from a std::shared_ptr to a reference (for example using operator*()) is much like a one-way function. I.e. you can get the reference from a std::shared_ptr but it is very hard to get back the std::shared_ptr from the reference. I can think of two ways to get back the std::shared_ptr once you decayed it to a reference, but one requires you to change the object (deriving from std::enable_shared_from_this<Building>) and the other just smells very badly of unclean code (creating a new std::shared_ptr with a no-op deleter to the address of the reference). So I would not recommend either ways.
Instead either choose a design which fits your problem domain, as shown above. Or keep the std::shared_ptr from decaying. If you pass them around as (const)-references to the std::shared_ptr this will not actually cost much more than just passing around the pointer itself.
Based on your "edit 2", I think I see your misunderstanding. These are two completely unrelated shared pointers:
Building m;
shared_ptr<Building> a(new Building(m));
shared_ptr<Building> b(new Building(m));
They will not match inside a std::set.
However, these are related pointers:
Building m;
shared_ptr<Building> a(new Building(m));
shared_ptr<Building> b = a;
So they will match inside a std::set.
Essentially, the comparisons are performed on the pointers, not on the underlying objects.
To answer your question
how does count compare shared pointers?
The comparison is done using the std::shared_ptr's get() method, meaning the managed pointers are compared. Conserning std::set<std::shared_ptr<T>>, the relevant comparison is bool operator<.
See here for more information.
I want to make a function that checks if a shared pointer exists in it.
I don't think you do.
shared_ptr<Building> mm(new Building(m));
if (this->Buildings.count(mm) == 0){
How can the shared pointer mm exist in the set when you've just created it there, and it points to a brand new object you've just created? How could they have got in the set between you creating them and looking for them in the set?
I think you want to check if a Building exists in it, by comparing the building's values, you don't care if a specific object or a specific shared pointer is in the set.
You could either search the set, comparing m to the building pointed to by every element:
void Garage::addCar(Car& n, Building& m){
bool found = false;
for (auto& shptr : Buildings)
{
if (*sp == m) // dereference shared_ptr to compare the Building
{
found = true;
break;
}
}
or use a custom comparison in the set, as in this answer.

Pointer Reference Pattern - Common use?

In a system where current object is operated by other contained objects, when reference to current object is passed, it appears that the link goes on and on....without any end ( For the code below, Car->myCurrentComponent->myCar_Brake->myCurrentComponent->myCar_Brake->myCurrentComponent ....).
ICar and Car->myCurrentComponent->myCar_Brake refer to same address, point to same objects. It's like Car contains Brake which refers to Car.
In fact, Car is the only object, myCar_Brake and myCar_Speed just refer(point) to it.Is this kind of use of reference and pointer normal? Are there any potential problem with this approach?
Sample Code
class Brake
class C
class Car
{
public:
Car();
// Objects of type B and C.
Brake* myBrake;
Speed* mySpeed;
// Current component under action.
Component* myCurrentComponent;
}
/******************************/
// Constructor
Car::Car()
{
myBrake = new Brake(*this);
mySpeed = new Speed(*this);
myCurrentComponent = myBrake;
}
/******************************/
class Brake: public Component
{
public:
Brake(Car&);
// Needs to operate on A.
Car* myCar_Brake;
}
// Constructor
Brake::Brake(Car&)
{
myCar_Brake = Car;
}
/******************************/
class Speed
{
public:
Speed(Car&);
// Needs to operate on A.
Car* myCar_Speed;
}
// Constructor
Speed::Speed(Car&)
{
myCar_Speed = Car;
}
/****************************/
There's no fundamental problem with having circular references in your object graph, so long as you understand that and don't try to traverse your object graph without keeping track of which objects you've encountered. To specifically answer your question, having circular references between objects is relatively common; it's the way a doubly-linked list works, for example.
Although, as Paul mentions, there is no problem with having circular references, the above code example is totally missing encapsulation and is not memory leak safe.
Does it make sense to allow something like this?
Speed::Speed(Car& value)
{
myCar_Speed = value;
// WTF code below
value->myCurrentComponent->myCar_Brake = NULL;
}
Also,
Car::Car()
{
myBrake = new Brake(*this);
mySpeed = new Speed(*this);
//if Speed::Speed(Car&) throws an exception, memory allocated for myBrake will leak
myCurrentComponent = myBrake;
}
Never use raw pointers without some kind of a resource manager.
Without debating the validity of the actual object structure of the relation of Car, Break and Speed, this approach has one minor problem: it can be in invalid states.
If - something - goes wrong, it is possible in this setup, that a Car instance#1 has a Break instance#2 that belongs to a Car instance#3. A general problem with doubly-linked lists too - the architecture itself enables invalid states. Of course careful visibility modifier choosing and good implementation of functions can guarantee it will not happen. And when its done and safe, you stop modifying it, take it as a 'black box', and just use it, thus eliminating the probability of screwing it up.
But, I'd personally recommend to avoid architectures that allow invalid states for high level, constantly maintained code. A doubly-linked list is a low level balck box code that will most likely not need any code changes, like ever. Can you say that about your Car, Break and Speed?
If a Car had a Break and Speed, and Break and Speed would not know of their "owning Car", it would be impossible to make and invalid state. Of course, it might not suit the concrete situation.