views:

104

answers:

4

I have been reading an article about C++ interfaces (http://accu.org/index.php/journals/233) and I am completely lost at the part where it says all the virtual member functions should be made private (the section titled "Strengthening the Separation"). It just does not make sense to me at all.

According to the author, the code is like this:

class shape {
public:
  virtual ~shape();
  virtual void move_x(distance x) = 0;
  virtual void move_y(distance y) = 0;
  virtual void rotate(angle rotation) = 0;
  //...
};

class line : public shape {
public:
  line(point end_point_1, point end_point_2);
  //...
private:
  virtual ~line();
  virtual void move_x(distance x);
  virtual void move_y(distance y);
  virtual void rotate(angle rotation);
  //...
};

So we have a pure virtual function which is public, and its implementation (in the line class) which is private.

Could anybody explain how the move_x function can be called? Its access specifier is private, it will lead to an error if I try to do this:

line my_line(point(0,0), point(1,2));
my_line.move_x(-1); // does not compile

Similarly is it correct to say that the drawing interface (see earlier in the article)cannot access these functions either?

Thank you.

+6  A: 

The idea is that you'd use those methods via a reference or pointer to shape.

shape &s = my_line;
s.move_x(-1);

This could be justified on the grounds of "reveal only what you need to", or as a form of self-documentation. It proves that the methods are only called in the intended way.

Daniel Earwicker
It's considered better programming habit to force the programmer (yourself) to use only the Interface.
Ben
Can't say I like the idea very much; if I want a line that's what I want, not a shape that happens to be a line. If I have a function which only needs the methods provided by shape then I'll pass the line into that function as a shape, just can't see why you'd do this, +1 for the explanation though.
Patrick
I agree it's not life-changing advice. As shown by the two lines above, it doesn't actually restrict anything much - just causes a minor inconvenience if the user seems to need to break the rule.
Daniel Earwicker
Andy
Yes - except the part about RTTI. The compile-time type of the reference/pointer variable is `shape`, and at runtime it may be referring/pointing to a `line`.
Daniel Earwicker
+2  A: 

I think that the article highlights the rationale well in this quote:

Now, the only thing users can do with line is create instances of it. All usage must be via its interface - i.e. shape, thus enforcing a stronger interface/implementation separation. Before leaving this topic, it is important to get something straight: the point of enforcing the interface/implementation separation is not to tell users what to do. Rather, the objective is to underpin the logical separation - the code now explains that the key abstraction is shape, and that line serves to provide an implementation of shape.

That is, line is not by itself interesting. It's just an implementation of the shape interface, and there may be other implementations. You're particularly interested in the shape interface. Hence, you should only access the implementation through this interface, and not as a standalone class.

Eli Bendersky
+4  A: 

If you have in instance of the line object, you might be tempted to call it's methods. But if the only way you can get at them is by asking for it's shape interface, then the object looks to less like an object and more like a collection of interfaces.

This makes more sense if you imagine line implementing more than one interface.

John Knoeller
+3  A: 

This advice is applicable to homogeneous hierarchies only -- that is, hierarchies in which derived classes introduce no new functions (except constructors maybe) and just override base class functions. In this case you obviously don't need to work with line instance directly -- only via pointer/reference to shape.

When you have less homogeneous hierarchy, this advice hasn't much sense: how would anyone apply it to cases when derived class introduces new functions, or inherits them from another base class? In this case you sometimes want to work directly with objects of derived class directly, and this advice would lead to inconveniences only.

Further development of this idea -- less radical and usable in more contexts -- Non-Virtual Interface (NVI) by Herb Sutter.

Alexander Poluektov
+1, it also inhibits the use of covariant return types
David Rodríguez - dribeas