views:

133

answers:

4

Which are the guidelines for choosing between template duck-typing and pure virtual base class inheritance? Examples:

// templates
class duck {
    void sing() { std::cout << "quack\n"; }
};

template<typename bird>
void somefunc(const bird& b) {
    b.sing();
}

// pure virtual base class
class bird {
    virtual void sing() = 0;
};

class duck : public bird {
    void sing() { std::cout << "quack\n"; }
}

void somefunc(const bird& b) {
    b.sing();
}
+4  A: 

With template duck-typing, you are doing static polymorphism. Thus, you cannot do things like

std::vector<bird*> birds;
birds.push_back(new duck());

However, since you are relying on compile time typing, you are a little most efficient (no virtual call implies no dynamic dispatch (base on the dynamic type)).

Scharron
Your `birds` are subject to slicing, use pointers instead.
Georg Fritzsche
@Scharron. Virtual calls do not cause "dynamic type checking" or anything of the sort. C++ never performs type checking at runtime.
John
@Georg I don't really get your comment. Even with pointers, the code won't work, slicing is unrelated.
Helltone
@John : sorry, I simplified. I meant dynamic dispatch. Edited. Thanks :-)
Scharron
@scharron: See [object slicing](http://en.wikipedia.org/wiki/Object_slicing) - you create a temporary `duck`, but it will be *sliced* to a `bird` when being copied into the vector. You also only get polymorphic behaviour for pointer or reference types.
Georg Fritzsche
@Georg ok so you were talking about Sharron's code... he said you *cannot* do things like that.
Helltone
@Georg yeah, right. edited with pointers :-)
Scharron
@hell: (Oops, that comment was meant to be adressed to you.) Yes, but the point was that you can't sensibly do that for dynamic polymorphism either.
Georg Fritzsche
+2  A: 

If having the "template nature" of things propagate widely is OK with you, templates ("compile-time duck typing") can give you blazing speed (avoiding the "level of indirection" that's implicit in a virtual-function call) though maybe at some cost in memory footprint (in theory, good C++ implementations could avoid that memory overhead related to templates, but I don't feel very confident that such high-quality compilers will necessarily be available on all platforms where you need to port;-). So, at least pragmatically, it's something of a speed/memory trade-off. If the operations you're doing are so super-slow as I/O, then maybe the relatively tiny speed gain from avoiding a virtual call isn't really material to your use case.

Alex Martelli
A: 

They are two completely different things. One is not an alternative to the other. The template function provides a general operation somefunc() which applies to a whole class of types, not just birds. The type of its parameter must be known at compile-time. The virtual method provides a runtime polymorphic operation specific to birds. The exact type of the parameter (this) need not be known at compile-time.

Since they provide different functionality, and are not in conflict with each other, it's rare that you ever need to decide between the two approaches. Decide what functionality you need, and the sensible approach will be obvious. It may even be a combination of the two.

(btw, the term "duck typing" is misused here. Neither approach is duck typing. You should drop the phrase from your C++ lexicon. )

John
I strongly disagree with your answer at many points. Templates can be used in many ways in C++, one of them is effectively duck-typing, and you should inform yourself better about it. Secondly, I also disagree with the part `Decide what functionality you need, and the sensible approach will be obvious`. Programming is NOT always straight-forward and design choices are NOT always obvious.
Helltone
A: 

Compile time vs. Runtime. If you want compile time binding you need to use templates. If you don't know the types at compile time, you should use virtual inheritence.

Mike