tags:

views:

178

answers:

6

I have an (for C++ programmers better than me) simple problem with classes and pointers. I thought about posting example code describing my problem but I found it easier to just explain it in words.

Assuming I have three classes:

  • Class A: The main class - it contains an instance of both B and C.
  • Class B: This class contains a method that outputs some string, call it Greet().
  • Class C: This one has a method too, but that method has to call Greet() in the instance of B that is located in class A. Let's name it DoSomethingWithB()

So the program starts, in the main function I create an instance of A. A, again, creates instances of B and C. Then, A calls C.DoSomethingWithB();.

And there my problem begins: I can't access B from inside C.

Obviously, I will need to pass a pointer to B to the DoSomethingWithB() function so that I can call B.Greet() from inside C

Long explanation, short question: How do I do this?

Example code incoming:

#include <iostream>
using namespace std;

class B
{
public:
    void Greet( )
    {
        cout<<"Hello Pointer!"<<endl;
    }
};

class C
{
public:
    void DoSomethingWithB( )
    {
        // ... b.Greet( ); Won't work obviously
    }
};

class A
{
public:
 B b; // Not caring about visibility or bad class/variable names here
 C c;
 void StartTest( )
 {
      c.DoSomethingWithB( );
 }
};

int main( )
{
    A mainInstance;
    mainInstance.StartTest();
}
A: 
class C 
{ 
public: 
    C (B & b) : b(b) {}
    void DoSomethingWithB( ) 
    { 
        // ... b.Greet( ); Use b;
    } 
private:
    B & b;
}; 

class A 
{ 
public: 
 B b; // Declare b before c! 
 C c; 
 A() : c (b) {}
 void StartTest( ) 
 { 
      c.DoSomethingWithB( ); 
 } 
}; 
Alexey Malistov
+5  A: 

Wouldn't you simply pass a pointer or reference to he B object?

class C 
{ 
public: 
    void DoSomethingWithB( B& b) 
    { 
        b.Greet( ); // will work fine 
    } 
}; 

class A 
{ 
public: 
 B b; // Not caring about visibility or bad class/variable names here 
 C c; 
 void StartTest( ) 
 { 
      c.DoSomethingWithB( b); 
 } 
};

If the DoSomethingWithB() function won't modify the passed in B instance, you should mark the reference const so it can be called with a const B object (for example if the owning A object happens to be const):

void DoSomethingWithB( B const& b);

You have a few options for how to pass the B object to the function:

  • as a reference (void DoSomethingWithB( B& b)) which will let the function modify the passed in object. Changes will be refelected in the object that's passed in.

  • as a const reference (void DoSomethingWithB( B const& b)) which won't let the function modify the passed in object (unless the constness is cast away - something which can lead to undefined behavior if done on an object the is truely const)

  • as a pointer or const pointer to a B object (void DoSomethingWithB( B* b) or void DoSomethingWithB( B const* pb) ). These have similar performance to passing by reference, but the function could be passed a NULL pointer which needs to be dealt with properly (by not dereferencing it in that case). Also, the call of the function would need to change slightly to pass the address of the B object:

    c.DoSomethingWithB( &b);
    
  • as a pass-by-value parameter (void DoSomethingWithB( B b)). This has difference that the function can do whatever it likes with theo bject passed in and it won't affect the originally passed object since the function is dealing with a copy. The disadvantage is that passing the parameter causes a copy to be made which might be expensive. You could also pass in a const value, but there's little to recommend that over passing a const reference.

Note that when chosing the parameter passing method, you should first chose based on the sematics of what you need the function to do (or not do). Worry about efficiency later. Always first design and code for correctness - worry about efficiency only after you have the design and code correct.

Michael Burr
That's what I was looking for, not so familiar with pointers yet. Is that the most efficient way?
lamas
I'd also mention **const** reference here, just to show that option.
Nikolai N Fetissov
I wasn't sure if I was missing something because your question contained a fiar bit of knowlege of class use and visibilty; this seemed too straightforward of an answer. But everyone needs to learn from the beginning; it's just the question seemed to indicate that there might be more to it.
Michael Burr
@Nikolai - I didn't mention `const` becuase it wasn't clear if the `DoSomethingWithB()` function would modify the `B` instance. I'll add a brief mention, though.
Michael Burr
@lamas - pointers and references are quite efficient. Given the short example, I'd lean toward using a reference because there's no apparent reason to have to deal with a NULL pointer. There's no real efficiency difference between pointers and references. References in general are more efficient than pass-by-value which would have to make a copy of the parameter.
Michael Burr
+2  A: 

You can do it just as you said -- pass a pointer (or a reference) to B in to DoSomethingWithB():

class C
{
public:
    void DoSomethingWithB(B & bInstance)
    {
        bInstance.Greet( ); // should work fine!
    }
};

Then you'll invoke it like so:

class A
{
public:
    B b; // Not caring about visibility or bad class/variable names here
    C c;
    void StartTest( )
    {
        c.DoSomethingWithB( b );
    }
};

I'd suggest using the reference approach here rather than a pointer, since:

  1. Your object is an automatic class member, and
  2. Passing a null B object into the function is not meaningful in this case.
mwigdahl
+3  A: 

Change the functions to the following:

void DoSomethingWithB(B& b)
{
    b.Greet();
}

... and in A ...

c.DoSomethingWithB(b);
Peter Alexander
A: 

In class C, declare the method DoSomethingWithB() like this:

void DoSomethingWithB( B* b )
{
   b->Greet();
}

And in class A call it like this:

void StartTest()
{
    c.DoSomethingWithB( &b );
}

Since you mentioned pointers, I answered using pointers. In C++ however, you should try to use const references whenever you can. That would of course require a small change to the existing code:

void DoSomethingWithB( const B& b )
{
   b.Greet();
}

// and

void StartTest()
{
    c.DoSomethingWithB( b );
}
zdawg
A: 

I can't access B from inside C

Instead of having C call methods in B, why not have C return information to the caller so it can do the operation?

When I hit these I've found it's because I've got my classes organized poorly. Usually if I rethink them the difficulty disappears with a new organization.

Jay