views:

261

answers:

6

A big reason why I use OOP is to create code that is easily reusable. For that purpose Java style interfaces are perfect. However, when dealing with C++ I really can't achieve any sort of functionality like interfaces... at least not with ease.

I know about pure virtual base classes, but what really ticks me off is that they force me into really awkward code with pointers. E.g. map<int, Node*> nodes; (where Node is the virtual base class).

This is sometimes ok, but sometimes pointers to base classes are just not a possible solution. E.g. if you want to return an object packaged as an interface you would have to return a base-class-casted pointer to the object.. but that object is on the stack and won't be there after the pointer is returned. Of course you could start using the heap extensively to avoid this but that's adding so much more work than there should be (avoiding memory leaks).

Is there any way to achieve interface-like functionality in C++ without have to awkwardly deal with pointers and the heap?? (Honestly for all that trouble and awkardness id rather just stick with C.)

A: 

Considering C++ doesn't require generic parameter constraints like C#, then if you can get away with it you can use boost::concept_check. Of course, this only works in limited situations, but if you can use it as your solution then you'll certainly have faster code with smaller objects (less vtable overhead).

Dynamic dispatch that uses vtables (for example, pure virtual bases) will make your objects grow in size as they implement more interfaces. Managed languages do not suffer from this problem (this is a .NET link, but Java is similar).

280Z28
+2  A: 

Template MetaProgramming is a pretty cool thing. The basic idea? "Compile time polymorphism and implicit interfaces", Effective C++. Basically you can get the interfaces you want via templated classes. A VERY simple example:

template <class T>
bool foo( const T& _object )
{
    if ( _object != _someStupidObject && _object > 0 )
        return true;
    return false;
}

So in the above code what can we say about the object T? Well it must be compatible with '_someStupidObject' OR it must be convertible to a type which is compatible. It must be comparable with an integral value, or again convertible to a type which is. So we have now defined an interface for the class T. The book "Effective C++" offers a much better and more detailed explanation. Hopefully the above code gives you some idea of the "interface" capability of templates. Also have a look at pretty much any of the boost libraries they are almost all chalk full of templatization.

DeusAduro
Though I don't really understand how your example leads to anything like interfaces I'll make sure to check out that book (esp. that chapter) :)
Junier
Ok I read that section and I understand what you were going for. This sort of thing could be useful. I guess one would have to leave a comment in the template with the requirements of the implicit interface for it to be really useful (and avoid making people read through all the code)
Junier
Indeed, you would. There are some pretty cool things people have done, the boost::spirit parser library is a neat example.
DeusAduro
Also note that I wasn't necessarily talking about interfaces in terms of their technical (ie. Java) definition, I'm not even sure what this is. But to me an interface is a generic way of defining a set of requirements which an object must adhere too. Ie. will polymorphic derived types and pure virtual base class functions, we require that any derived object must have a certain interface. Thats just my thoughts on it though, again I was getting at any technical definition.
DeusAduro
By the way, this isn't really template meta-programming, it's just using templates. Template meta-programming is using templates as a Turing-complete functional language, evaluated at compile time.
Steve Jessop
A: 

I think the answer to your question is no - there is no easier way. If you want pure interfaces (well, as pure as you can get in C++), you're going to have to put up with all the heap management (or try using a garbage collector. There are other questions on that topic, but my opinion on the subject is that if you want a garbage collector, use a language designed with one. Like Java).

One big way to ease your heap management pain somewhat is auto pointers. Boost has a nice automatic pointer that does a lot of heap management work for you. The std::auto_ptr works, but it's quite quirky in my opinion.

You might also evaluate whether you really need those pure interfaces or not. Sometimes you do, but sometimes (like some of the code I work with), the pure interfaces are only ever instantiated by one class, and thus just become extra work, with no benefit to the end product.

Michael Kohne
Java is too slow for programs that you plan on running over and over again. The main reason that I'm using c++ right now is to extend NS2 (network simulator) so using boost is really not an option. Though, I'll look into boost auto pointers for future uses. As far as whether I really need the interfaces, the answer is no. I don't NEED them. Just like I don't need OOP. But interfaces do make code more reusable :-p but I know better than to put myself thru so much trouble for nothing.
Junier
The boost shared_ptr (or a close clone thereof) is becoming part of the new standard and is available with many new compilers as part of the `tr1`extension to the library: `std::tr1::shared_ptr<Type>`
David Rodríguez - dribeas
+4  A: 

You can use boost::shared_ptr<T> to avoid the raw pointers. As a side note, the reason why you don't see a pointer in the Java syntax has nothing to do with how C++ implements interfaces vs. how Java implements interfaces, but rather it is the result of the fact that all objects in Java are implicit pointers (the * is hidden).

Michael Aaron Safyan
A: 

While auto_ptr has some weird rules of use that you must know*, it exists to make this kind of thing work easily.

auto_ptr<Base> getMeAThing() {
    return new Derived();
}


void something() {
    auto_ptr<Base> myThing = getMeAThing();
    myThing->foo();  // Calls Derived::foo, if virtual
    // The Derived object will be deleted on exit to this function.
}

*Never put auto_ptrs in containers, for one. Understand what they do on assignment is another.

Mike Elkins
std::auto_ptr cannot be used with standard containers, so it cannot be use to replace the raw pointer in the question code. You would need a boost::shared_ptr or std::tr1::shared_ptr
David Rodríguez - dribeas
A: 

This is actually one of the cases in which C++ shines. The fact that C++ provides templates and functions that are not bound to a class makes reuse much easier than in pure object oriented languages. The reality though is that you will have to adjust they manner in which you write your code in order to make use of these benefits. People that come from pure OO languages often have difficulty with this, but in C++ an objects interface includes not member functions. In fact it is considered to be good practice in C++ to use non-member functions to implement an objects interface whenever possible. Once you get the hang of using template nonmember functions to implement interfaces, well it is a somewhat life changing experience. \