views:

450

answers:

11

I'm trying to properly encapsulate a class A, which should only be operated on by class B.

However, I want to inherit from class B.

Having A friend B doesn't work -- friendship isn't inherited.

What's the generally accepted way of accomplish what I want, or am I making a mistake?

To give you a bit more color, class A represents a complex system's state. It should only be modified by B, which are actions that can be applied to change class A's state.

+4  A: 

It sounds like you may need to do a redesign; your class A represents a State, but your Class B represents a set of actions. There's a relationship there, but it's not an inheritance relationship. I'd suggest composition; you want more of a HASA relationship than an ISA relationship, as far as I can tell.

McWafflestix
Was thinking the same thing, but wasn't sure if he just wasn't giving enough info
windfinder
This is especially true if Class B is going to contain multiple instances of Class A (multiple states). http://en.wikipedia.org/wiki/State_pattern
Jeff L
As I understand it, he wants A to be the system and B to be a base class from which different actions inherit, not B to inherit from A.
Ari
+2  A: 

The most straightforward way to do this is simply to have B contain an A:

class B { protected: A a_; };

Then, you can write a class C which inherits from B and is able to manipulate A. If C shouldn't be able to do arbitrary things to the A, then make the A private in B and provide protected methods in B that C can use to do approved things to the A, like so:

class B { private: A a_; protected: void doSomethingToA(); };

aem
He wants to inherit from class B.
Partial
I don't like this. It says that A (the system) is a part of B (action), i.e., the action has a system. This makes no sense.
Ari
Hmm, Ari may be right about this, though it's difficult to tell what the OP's intent was without some clarification.
aem
A: 

I cant see why you would want to inherit. Make everything in A private and friend B. B then has a member of A which it can freely manipulate.

mizipzor
+2  A: 

Keeping everything as is, the easiest thing to do is to add protected methods to B that give access to the equivalent feature of A it would need. This opens the encapsulation to just subclasses of B.

Lou Franco
+3  A: 

If I understand you correctly, you want to have B and it's derivatives to have access to the internal implementation of class A, yes?

Unfortunately, C++ does not have the concept of "internal" protection levels that languages like C# and Java posses.

You can consider using the private implementation paradigm (pimpl) - also known as opaque pointers, to expose functionality within your system using public access levels, that consumers of A and B would not see.

LBushkin
+1, I think this is a good use case for Pimpl.
Kristo
A: 

The way you describe this it sounds more like composition rather than inheritance. E.g.

class ComplexMachine {
  public:
    setState(int state);
};

class Operator {
   public:
   Operator(ComplexMachine & m) :_m(m) {};

   void drive() { _m->setState(1); }
   void turn() { _m->setState(2); }
   void stop() { _m->setState(0); }

   private:
   ComplexMachine _m;   
};

class SmoothOperator : public Operator { }
+1  A: 

Containment is the way to go (class B contains private member of type A) unless B needs to override some virtuals in A, in which case private inheritance is the closest thing.

Nikolai N Fetissov
+3  A: 

I assume you want to allow descendants of B to access A directly? If A and B are tightly coupled, you can make A a protected class definition within B itself, instead of being an independent definition. E.G.

class B
{
protected:
    class A
    {
    };
};

Another idea is to create protected methods on B that delegate their actions to A. E.G.

class A
{
friend class B;
private:
    void DoSomething();
};

class B
{
protected:
    void DoSomething(A& a) { a.DoSomething(); }
};
Mark Ransom
A: 

Working with the bits of information you have given:

Class B should be responsible for preserving the invariants of class A, and class B should be the only way to manipulate A. Any client - derived class or caller - should not need to know that A exists.

(From design POV, there's even no need for A to exist, but I have encountered enough practical reasons for such a separation that I won't hold it against you ;))

This might require a lot of boilerplate code to be written, or some trickery with the interface. e.g. if client should be allowed to use class A to query information but not to modify it, B could hand out a const & to the aggregated A. With a compiler supporting __declspec(property) or similar, the syntactic pain can be eased.

peterchen
A: 

From what I understand from your question, you will need some polymorphism. You need an abstract class A and class B inherits class A. Also, the protected keyword allows the classes that inherit to have access to certain information while at the same time deny access to anything else. Here is a little example:

// dynamic allocation and polymorphism
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area (void) =0;
    void printarea (void)
      { cout << this->area() << endl; }
  };

class CRectangle: public CPolygon {
  public:
    int area (void)
      { return (width * height); }
  };

class CTriangle: public CPolygon {
  public:
    int area (void)
      { return (width * height / 2); }
  };

int main () {
  CPolygon * ppoly1 = new CRectangle;
  CPolygon * ppoly2 = new CTriangle;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  delete ppoly1;
  delete ppoly2;
  return 0;
}

Code taken from cplusplus.com (contains information on polymorphism and abstract classes too).

Partial
A: 

If you want to be sure that only B operates on A, make the instance of A private and expose a protected interface from B to its descendants.

class A
{
  public:
    void foo() {}
};

class B
{
  private:
    A a;

  protected:
    void CallAFoo() { a.foo() };
};

class C : public B
{
    void goo() { CallAFoo(); }
};
Magnus Skog