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.
精彩评论