views:

107

answers:

3

Hello,

I am trying to improve my knowledge on program architecture and recently arised a question to me which is related with this pointers issues I posted recently.

The thing is that in a simple hierarchy in which you have Class A with a pointers to Class B and the last to Class C. Do not confuse the with the inheritage property of the Object Oriented programming but basically what I am saying is that Class C is the child of Class B and Class B is the child of Class A.

The point is that I want to be able to access directly from Class A to Class C (the grandson in the analogy) with pointers. Some other members pointed out this is poor design, basically because if a delete an instance of class C from class B collection would leave a pointer to "nothing" in the Class A collection. Then, how is this modelled properly?

Thank you a lot!

Julen.

+1  A: 

I think what you are saying is that class C derives from class B which derives from class A. Don't confuse the class hierarchy with pointers to objects of a class. You can do what you are talking about with a single object (and a single pointer to an object). If you create a pointer of type C* to an object of type C you can access all public and protected methods defined in classes B and A. Alternately, if you implement virtual methods you can create a pointer of type A* to an object of type C. At runtime, the vtable will be used to automatically find the lowest level implementation of that virtual method (i.e.- from Class C if defined there, else from class B if defined there, else from class A). There are a large number of good resources for learning the basics of C++. I'm sure there are topics on SO with such a list if you search.

EDIT

Here is one such link: http://stackoverflow.com/questions/70159/what-is-the-best-source-to-learn-c

RickNotFred
Sorry, maybe the example was misleading. No, there is no inheritance at all. Is basically Class A it's let's say the Car and Class B are the wheels whereas the Class C are the screws part of those wheels. The thing is that I want to the car to know directly all these screws.
Julen
+5  A: 

Unfortunately, you're just reinventing the wheel. Change your approach, all that pointer-stuff could be actually managed automatically.

If possible, use composition. Let object of class A hold an object of class B, which would hold an object of class C. That obvious and simple approach could save you a huge amount of time and make the structure of your app better and "cleaner".

If your classes could be treated of objects of the same type (for example, if they share the same interface), then derive your C from B and derive B from A. Right after that you would have to think of their shared interface - in terms of virtual functions in your class A, which acts like a base class. This is actually a tricky moment, but once you get used to planning your interfaces this way, you just can't think of doing it somehow else.

Also to mention, if even it seems like "your current problem can't be modelled via dynamic polymorphism" or you "just can't think of a proper interface", try again. And don't try to invent new ways of program architecture building, but simply get used to existing ones.

Kotti
What you're referring to is known as the Composite Pattern: http://en.wikipedia.org/wiki/Composite_pattern
Emile Cormier
Thank you Kotti. But, if I understand correctly, there isnt any type on inheritance between my classes. Just that B is a part of A, and C is part of B. And at the same time A has to be aware of all C parts. Maybe the thing is that I should not use pointers to model this approach.
Julen
+2  A: 

Instead of making class A aware of every class C, consider using the Composite Pattern:

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <stdexcept>

//------------------------------------------------------------------------------
class Component
{
public:
    typedef boost::ptr_vector<Component> Children;

    virtual void print() = 0;
    // Other operations

    virtual bool isLeaf() {return true;}

    virtual Children& children()
        {throw std::logic_error("Leaves can't have children");}
};

//------------------------------------------------------------------------------
class Composite : public Component
{
public:
    void print()
    {
        BOOST_FOREACH(Component& child, children_)
        {
            child.print();
        }
    }

    bool isLeaf() {return false;}

    Children& children() {return children_;}

private:
    Children children_;
};

//------------------------------------------------------------------------------
class Nut : public Component
{
public:
    Nut(std::string info) : info_(info) {}
    void print() {std::cout << info_ << std::endl;}

private:
    std::string info_;
};

//------------------------------------------------------------------------------
class Bolt : public Component
{
public:
    Bolt(std::string info) : info_(info) {}
    void print() {std::cout << info_ << std::endl;}

private:
    std::string info_;
};

//------------------------------------------------------------------------------
class Wheel : public Composite
{
public:
    Wheel(std::string info) : info_(info) {}
    void print()
    {
        std::cout << info_ << std::endl;
        Composite::print();
    }

private:
    std::string info_;
};

//------------------------------------------------------------------------------
class Vehicle : public Composite
{
public:
    Vehicle(std::string info) : info_(info) {}
    void print()
    {
        std::cout << info_ << std::endl;
        Composite::print();
        std::cout << "\n\n";
    }

private:
    std::string info_;
};

//------------------------------------------------------------------------------
int main()
{
    Wheel* wheel1 = new Wheel("Wheel1");
    wheel1->children().push_back(new Nut("Nut11"));
    wheel1->children().push_back(new Nut("Nut12"));
    wheel1->children().push_back(new Bolt("Bolt11"));
    wheel1->children().push_back(new Bolt("Bolt12"));

    Wheel* wheel2 = new Wheel("Wheel2");
    wheel2->children().push_back(new Nut("Nut21"));
    wheel2->children().push_back(new Nut("Nut22"));
    wheel2->children().push_back(new Bolt("Bolt21"));
    wheel2->children().push_back(new Bolt("Bolt22"));

    Vehicle bike("Bike");
    bike.children().push_back(wheel1);
    bike.children().push_back(wheel2);

    bike.print();
}

This program outputs:

Bike
Wheel1
Nut11
Nut12
Bolt11
Bolt12
Wheel2
Nut21
Nut22
Bolt21
Bolt22

Note that when bike.print() is called, print is called recursively on all children. This is how you can perform operations on all children without the grand-parent knowing about all its children.

The Visitor Pattern works very well with the Composite pattern, so I suggest you read up on that one too. Especially if you have many operations that can be implemented in terms of more basic ones.

Emile Cormier