C++ template duck-typing vs pure virtual base class inheritance
Asked Answered
F

5

14

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();
}
Fumble answered 23/7, 2010 at 16:20 Comment(1)
Nice pun :) (more characters)Mcclimans
K
12

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 more efficient (no virtual call implies no dynamic dispatch (base on the dynamic type)).

Kerekes answered 23/7, 2010 at 16:25 Comment(6)
@Scharron. Virtual calls do not cause "dynamic type checking" or anything of the sort. C++ never performs type checking at runtime.Claypool
@Georg I don't really get your comment. Even with pointers, the code won't work, slicing is unrelated.Fumble
@Claypool : sorry, I simplified. I meant dynamic dispatch. Edited. Thanks :-)Kerekes
@scharron: See 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.Calctufa
@Georg ok so you were talking about Sharron's code... he said you cannot do things like that.Fumble
@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.Calctufa
R
3

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.

Rompers answered 23/7, 2010 at 16:25 Comment(0)
T
2

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.

Tenderloin answered 23/7, 2010 at 18:52 Comment(1)
Nice and short answer. It says everything an intermediate programmer needs to know to decide which way to choose (once he knows when he needs his types to be dynamic, such as storing them in a container of the abstract type). I wonder why this didn't get upvoted for almost 3 years. Now it did :)Borage
C
-1

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. )

Claypool answered 23/7, 2010 at 17:25 Comment(1)
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.Fumble
A
-3

@John is right. If you have two covariant type parameters you have no choice, you have to use templates. Object oriented techniques provide run-time dispatch but it is only available for types whose methods have at most one variant argument (the object).

Most interesting problems involve relations which are N-ary with N>1 therefore you will usually have no choice but to use templates. Please examine the standard library to see which technique is used most.

Acro answered 28/11, 2010 at 3:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.