How to achieve "virtual template function" in C++
Asked Answered
A

9

47

first off: I have read and I know now that a virtual template member function is not (yet?) possible in C++. A workaround would be to make the class a template and then use the template-argument also in the member-function.

But in the context of OOP, I find that the below example would not be very "natural" if the class was actually a template. Please note that the code is actually not working, but the gcc-4.3.4 reports: error: templates may not be ‘virtual’

#include <iostream>
#include <vector>

class Animal {
    public:
        template< class AMOUNT >
        virtual void eat( AMOUNT amount ) const { 
            std::cout << "I eat like a generic Animal." << std::endl; 
        }
        virtual ~Animal() { 
        }
};

class Wolf : public Animal {
    public:
        template< class AMOUNT >
        void eat( AMOUNT amount) const { 
            std::cout << "I eat like a wolf!" << std::endl; 
        }
        virtual ~Wolf() { 
        }
};

class Fish : public Animal {
    public:
        template< class AMOUNT >
        void eat( AMOUNT amount) const { 
            std::cout << "I eat like a fish!" << std::endl; 
        }
        virtual ~Fish() { 
        }
};

class GoldFish : public Fish {
    public:
        template< class AMOUNT >
        void eat( AMOUNT amount) const { 
            std::cout << "I eat like a goldfish!" << std::endl; 
        }
        virtual ~GoldFish() { 
        }
};

class OtherAnimal : public Animal {
        virtual ~OtherAnimal() { 
        }
};

int main() {
    std::vector<Animal*> animals;
    animals.push_back(new Animal());
    animals.push_back(new Wolf());
    animals.push_back(new Fish());
    animals.push_back(new GoldFish());
    animals.push_back(new OtherAnimal());

    for (std::vector<Animal*>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
        (*it)->eat();
        delete *it;
    }

    return 0;
}

So creating a "Fish< Amount > foo" is kind of strange. However, it seems desirable to me to provide an arbitrary amount of food to eat for each animal.

Thus, I am searching a solution about how to achieve something like

Fish bar;
bar.eat( SomeAmount food );

This becomes particularly useful when looking at the for-loop. One might like to feed a specific amount (FoodAmount) to all of the different animals (via eat() and bind1st() e.g.), it could not be done that easily, although I wound find this very inuitive (and thus to some extent "natural). While some might want to argue now that this is due to the "uniform"-character of a vector, I think/wish that it should be possible to achieve this and I really would like to know how, as this is puzzling me for quite some time now...

[EDIT]

To perhaps clarify the motivation behind my question, I want to program an Exporter-class and let different, more specialized classes derive from it. While the top-level Exporter-class is generally only for cosmetic/structural purpose, a GraphExporter-class is derived, that should again serve as a base-class for even more specialzed export. However, similar to the Animal-example, I would like to be able to define GraphExporter* even on specialized/derived classes (e.g. on SpecialGraphExplorer) but when calling "write( out_file )", it should call the appropriate member function for SpecialGraphExporter instead of GraphExporter::write( out_file).

Maybe this makes my situation and intentions clearer.

Best,

Shadow

Accusatorial answered 3/5, 2011 at 15:16 Comment(12)
What does fish.eat("string") do? What does wolf.eat(Fish()) do? Can you use an abstract base class Amount instead of trying to make it a template parameter?Handoff
Amount sounds an awful lot like a value, rather than a type, which makes me very confused about why you feel a template is necessary here.Conversable
May I ask why do you want to describe a quantity as a class? It seems for me that quantity type can well be known at compile time, i.e. size_t. That as well will allow you to pass different values. Or perhaps another example can demonstrate the need better.Obscurity
It's not MS specific, they are using an outdated version of gcc. If you want to play with newer features of C++ especially some of the nifty things from C++0x you need to be on newer than gcc 4.6+ or MSVC 10+Greet
I uses Amount here just for illustration purposes. One might think about it as a unit (kg, ton...).Accusatorial
I've read your question several times and I still can't understand what you're trying to accomplish with the templated function that couldn't be solved with a class that stores weight (or mass) and allows conversion to/from various units.Vipul
If you'd like to use units you should probably have a look at boost::units (boost.org/doc/libs/1_46_1/doc/html/boost_units.html)Admixture
Generally, such units aren't expressed as unique types, but as a single type that builds the scale factor into it. You might want to parameterize the type of food, such that a wolf can eat a pound of fish while a bear can eat a ton of human flesh, but that wouldn't be a case for templates, especially in the base class. eating would no longer be a common function of all animals.Conversable
Unfortunately, the example did not serve up that well as I previously thought it would... The question was not about realizing a unit-functionality or such. It is/was intended to reflect my point on a rather "natural" example, as each animal must eat. And I was looking for a convenient interface to realize a similar thing with an Exporter-class.Accusatorial
Hey hey - I found an actual implementation that you may be able to useAtal
In this other StackOverflow question, a user mentioned the "type erasure" technique, you might be interested in looking at it.Misdate
@wil +1 for seemingly being the only one understanding the question rather than discussing the validity of the toy example used...Anteater
A
38

After some thinking I recognized this as the classic multi-method requirement, i.e. a method that dispatches based on the runtime type of more than one parameter. Usual virtual functions are single dispatch in comparison (and they dispatch on the type of this only).

Refer to the following:

  • Andrei Alexandrescu has written (the seminal bits for C++?) on implementing multi-methods using generics in 'Modern C++ design'
    • Chapter 11: "Multimethods" - it implements basic multi-methods, making them logarithmic (using ordered typelists) and then going all the way to constant-time multi-methods. Quite powerful stuff !
  • A codeproject article that seems to have just such an implementation:
    • no use of type casts of any kind (dynamic, static, reinterpret, const or C-style)
    • no use of RTTI;
    • no use of preprocessor;
    • strong type safety;
    • separate compilation;
    • constant time of multimethod execution;
    • no dynamic memory allocation (via new or malloc) during multimethod call;
    • no use of nonstandard libraries;
    • only standard C++ features is used.
  • C++ Open Method Compiler, Peter Pirkelbauer, Yuriy Solodkyy, and Bjarne Stroustrup
  • The Loki Library has A MultipleDispatcher
  • Wikipedia has quite a nice simple write-up with examples on Multiple Dispatch in C++.

Here is the 'simple' approach from the wikipedia article for reference (the less simple approach scales better for larger number of derived types):

// Example using run time type comparison via dynamic_cast

struct Thing {
    virtual void collideWith(Thing& other) = 0;
}

struct Asteroid : Thing {
    void collideWith(Thing& other) {
        // dynamic_cast to a pointer type returns NULL if the cast fails
        // (dynamic_cast to a reference type would throw an exception on failure)
        if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
            // handle Asteroid-Asteroid collision
        } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
            // handle Asteroid-Spaceship collision
        } else {
            // default collision handling here
        }
    }
}

struct Spaceship : Thing {
    void collideWith(Thing& other) {
        if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
            // handle Spaceship-Asteroid collision
        } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
            // handle Spaceship-Spaceship collision
        } else {
            // default collision handling here
        }
    }
}

Atal answered 2/10, 2011 at 20:29 Comment(0)
D
17

Obviously, virtual member function templates are not allowed and could not be realized even theoretically. To build a base class' virtual table, there needs to be a finite number of virtual function-pointer entries. A function template would admit an indefinite amount of "overloads" (i.e. instantiations).

Theoretically-speaking, a language (like C++) could allow virtual member function templates if it had some mechanism to specify the actual (finite) list of instantiations. C++ does have that mechanism (i.e. explicit template instantiations), so I guess it could be possible to do this in a newer C++ standard (although I have no idea what trouble it would entail for compiler vendors to implement this feature). But, that's just a theoretical discussion, in practice, this is simply not allowed. The fact remains, you have to make the number of virtual functions finite (no templates allowed).

Of course, that doesn't mean that class template cannot have virtual functions, nor does it mean that virtual functions cannot call function templates. So, there are many solutions in that vein (like the Visitor pattern or other schemes).

One solution that, I think, serves your purpose (although it is hard to comprehend) elegantly is the following (which is basically a visitor pattern):

#include <iostream>
#include <vector>

struct Eater { 
  virtual void operator()(int amount) const = 0;
  virtual void operator()(double amount) const = 0;
};

template <typename EaterType>
struct Eater_impl : Eater {
  EaterType& data;
  Eater_impl(EaterType& aData) : data(aData) { };
  virtual void operator()(int amount) const { data.eat_impl(amount); };
  virtual void operator()(double amount) const { data.eat_impl(amount); };
};

class Animal {
  protected:
    Animal(Eater& aEat) : eat(aEat) { };
  public:
    Eater& eat;
    virtual ~Animal() { delete &eat; };
};

class Wolf : public Animal {
  private:
    template< class AMOUNT >
    void eat_impl( AMOUNT amount) const { 
      std::cout << "I eat like a wolf!" << std::endl; 
    }

  public:
    friend struct Eater_impl<Wolf>;        
    Wolf() : Animal(*(new Eater_impl<Wolf>(*this))) { };
    virtual ~Wolf() { };
};

class Fish : public Animal {
  private:
    template< class AMOUNT >
    void eat_impl( AMOUNT amount) const { 
      std::cout << "I eat like a fish!" << std::endl; 
    }
  public:
    friend struct Eater_impl<Fish>;
    Fish() : Animal(*(new Eater_impl<Fish>(*this))) { };
    virtual ~Fish() { };
};

int main() {
  std::vector<Animal*> animals;
  animals.push_back(new Wolf());
  animals.push_back(new Fish());

  for (std::vector<Animal*>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
    (*it)->eat(int(0));
    (*it)->eat(double(0.0));
    delete *it;
  };

  return 0;
};

The above is a neat solution because it allows you to define a finite number of overloads that you want in one place only (in the Eater_impl class template) and all you need in the derived class is a function template (and possibly additional overloads, for special cases). There is, of course, a bit of overhead, but I guess that a bit more thought could be put into it to reduce the overhead (additional reference storage and dynamic allocation of Eater_impl). I guess, the curiously recurring template pattern could probably be employed somehow to this end.

Dunghill answered 3/5, 2011 at 16:27 Comment(3)
Actually, C++ does have explicit template instantiations.Antidepressant
That's a great observation, Mikael. I was kind of hoping that with C++14 there'd be an allowable edge case, where the compiler observers an explicit instantiation pattern: that a template is declared but undefined [maybe even has "extern" specified"], so the non-accessible source file with have a finite number of instantiations that could be listed in the vtable. Then, if the subsequent classes implement them (which would also need to be as explicit instantiations), then everything would be peachy. I would think this would be achievable via name mangling.Camisole
I've added what I think may be a slightly simplified version here: Inheritance is direct, and rather than storing a reference, which means the ctor needs to be accounted for, I've just added a derived() method in the implementation class which handles the casting. In addition, I've extended the template to handle implementation for multiple generations (e.g., Animal -> Canine -> {Wolf, Dog}).Camisole
S
14

I think the visitor pattern can be a solution.

UPDATE

I finished my example:

#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>

class Animal;
class Wolf;
class Fish;

class Visitor
{
    public:
    virtual void visit(const Animal& p_animal) const = 0;
    virtual void visit(const Wolf& p_animal) const = 0;
    virtual void visit(const Fish& p_animal) const = 0;
};

template<class AMOUNT>
class AmountVisitor : public Visitor
{
    public:
    AmountVisitor(AMOUNT p_amount) : m_amount(p_amount) {}
    virtual void visit(const Animal& p_animal) const
    {
        std::cout << "I eat like a generic Animal." << std::endl;
    }
    virtual void visit(const Wolf& p_animal) const
    {
        std::cout << "I eat like a wolf!" << std::endl;
    }
    virtual void visit(const Fish& p_animal) const
    {
        std::cout << "I eat like a fish!" << std::endl;
    }


    AMOUNT m_amount;
};

class Animal {
    public:

        virtual void Accept(const Visitor& p_visitor) const
        {
            p_visitor.visit(*this);
        }

        virtual ~Animal() {
        }
};

class Wolf : public Animal {
    public:
        virtual void Accept(const Visitor& p_visitor) const
        {
            p_visitor.visit(*this);
        }
};

class Fish : public Animal {
    public:
        virtual void Accept(const Visitor& p_visitor) const
        {
            p_visitor.visit(*this);
        }
};

int main()
{
    typedef boost::shared_ptr<Animal> TAnimal;
    std::vector<TAnimal> animals;
    animals.push_back(TAnimal(new Animal()));
    animals.push_back(TAnimal(new Wolf()));
    animals.push_back(TAnimal(new Fish()));

    AmountVisitor<int> amount(10);

    for (std::vector<TAnimal>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
        (*it)->Accept(amount);
    }

    return 0;
}

this prints:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
Subjacent answered 3/5, 2011 at 15:55 Comment(5)
Thank you. This is a nice solution as far as I understood it and I think, that this could also work for my problem designing Exporters instead of Animals. However, there is one thing I am wondering about: Would it be possible to realize something like a fallback-mechanism here, if e.g. an Animal gets an amount to eat that it can't eat the way it would usually do, but would then fallback to the generic way of "eating"?Accusatorial
It is possible. For example you can use the chain-of-responsibility pattern in a visitor class. Just google "c++ chain-of-responsibility pattern".Subjacent
I don't understand why this answer has not a better score: this definitely is the best solution to implement virtual template function.Subservient
How would you apply the open/closed principle here if I wanted to add a new Animal (Bear) in my own program?Ammo
Thank you for commenting my 11,5 years old post! With this solution you have to modify both the Visitor and the AmountVisitor classes.Subjacent
C
5

Per Mikael's post, I have made another offshoot, using the CRTP and following Eigen's style of using derived() for an explicit subclass reference:

// Adaptation of Visitor Pattern / CRTP from:
// https://mcmap.net/q/205525/-how-to-achieve-quot-virtual-template-function-quot-in-c

#include <iostream>
using std::cout;
using std::endl;

class Base {
public:
  virtual void tpl(int x) = 0;
  virtual void tpl(double x) = 0;
};

// Generics for display
template<typename T>
struct trait {
  static inline const char* name() { return "T"; }
};
template<>
struct trait<int> {
  static inline const char* name() { return "int"; }
};
template<>
struct trait<double> {
  static inline const char* name() { return "double"; }
};

// Use CRTP for dispatch
// Also specify base type to allow for multiple generations
template<typename BaseType, typename DerivedType>
class BaseImpl : public BaseType {
public:
  void tpl(int x) override {
    derived()->tpl_impl(x);
  }
  void tpl(double x) override {
    derived()->tpl_impl(x);
  }
private:
  // Eigen-style
  inline DerivedType* derived() {
    return static_cast<DerivedType*>(this);
  }
  inline const DerivedType* derived() const {
    return static_cast<const DerivedType*>(this);
  }
};

// Have Child extend indirectly from Base
class Child : public BaseImpl<Base, Child> {
protected:
  friend class BaseImpl<Base, Child>;
  template<typename T>
  void tpl_impl(T x) {
    cout << "Child::tpl_impl<" << trait<T>::name() << ">(" << x << ")" << endl;
  }
};

// Have SubChild extend indirectly from Child
class SubChild : public BaseImpl<Child, SubChild> {
protected:
  friend class BaseImpl<Child, SubChild>;
  template<typename T>
  void tpl_impl(T x) {
    cout << "SubChild::tpl_impl<" << trait<T>::name() << ">(" << x << ")" << endl;
  }
};


template<typename BaseType>
void example(BaseType *p) {
  p->tpl(2);
  p->tpl(3.0);
}

int main() {
  Child c;
  SubChild sc;

  // Polymorphism works for Base as base type
  example<Base>(&c);
  example<Base>(&sc);
  // Polymorphism works for Child as base type
  example<Child>(&sc);
  return 0;
}

Output:

Child::tpl_impl<int>(2)
Child::tpl_impl<double>(3)
SubChild::tpl_impl<int>(2)
SubChild::tpl_impl<double>(3)
SubChild::tpl_impl<int>(2)
SubChild::tpl_impl<double>(3)

This snippet may be found in source here: repro:c808ef0:cpp_quick/virtual_template.cc

Camisole answered 16/4, 2017 at 17:56 Comment(0)
G
2

Virtual template function is not allowed. However you can use one OR the other here.

You could make an interface using virtual methods and implement your various animals in terms of having an eating interface. (i.e. PIMPL)

Less human intuitive would be having a non-member non-friend template function as a free function which could take templated const reference to any animal and make them eat accordingly.

For the record you don't need templates here. Pure virtual abstract method on the base class is enough to force and interface where all animals must eat and define how they do so with an override, providing a regular virtual would be enough to say all animals can eat but if they don't have a specific way then they can use this default way.

Greet answered 3/5, 2011 at 15:32 Comment(1)
I am not sure if I get your points completely right, but it seems to me, that it will provide the most convenient and intuitive solution to my problem. Could you please elaborate on this a bit in detail? Maybe by modifying the Animal-example code accordingly? After all, I want to program an Exporter-interface but I thought that this example would be more illustrative.Accusatorial
H
2

You can create a template class with virtual function, and implement the function in the derived class without using template in the follwing way:

a.h:

template <class T>
class A
{
public:
    A() { qDebug() << "a"; }

    virtual A* Func(T _template) { return new A;}
};


b.h:

class B : public A<int>
{
public:
    B();
    virtual A* Func(int _template) { return new B;}
};


and the function CTOR and call 

  A<int>* a1=new B;
    int x=1;
    a1->Func(x);

unfortunately i havn't found a way to create a virtual function with template parameters without declaring the class as a template and it template type on the dervied class

Handspring answered 15/7, 2015 at 10:56 Comment(0)
C
1

I have copied your code and modified it, so now it should work exactly as you want:

        #include <iostream>
        #include <vector>

        //defined new enum type
        enum AnimalEnum
        {
           animal,
           wolf,
           fish,
           goldfish,
           other
        };

        //forward declarations
        class Wolf;
        class Fish;
        class GoldFish;
        class OtherAnimal;

        class Animal {
            private:
            AnimalEnum who_really_am_I;
            void* animal_ptr;
            public:
                //declared new constructors overloads for each type of animal
                Animal(const Animal&);
                Animal(const Wolf&);
                Animal(const Fish&);
                Animal(const GoldFish&);
                Animal(const OtherAnimal&);
                template< class AMOUNT >
                /*removed the virtual keyword*/ void eat( AMOUNT amount ) const { 
                    switch (this->who_really_am_I)
                    {
                       case AnimalEnum::other: //You defined OtherAnimal so that it doesn't override the eat action, so it will uses it's Animal's eat
                       case AnimalEnum::animal: std::cout << "I eat like a generic Animal." << std::endl; break;
                       case AnimalEnum::wolf: ((Wolf*)this->animal_ptr)->eat(amount); break;
                       case AnimalEnum::fish: ((Fish*)this->animal_ptr)->eat(amount); break;
                       case AnimalEnum::goldfish: ((GoldFish*)this->animal_ptr)->eat(amount) break;
                    }
                }
                void DeleteMemory() { delete this->animal_ptr; }
                virtual ~Animal() { 
                   //there you can choose if whether or not to delete "animal_ptr" here if you want or not
                }
        };

        class Wolf : public Animal {
            public:
                template< class AMOUNT >
                void eat( AMOUNT amount) const { 
                    std::cout << "I eat like a wolf!" << std::endl; 
                }
                virtual ~Wolf() { 
                }
        };

        class Fish : public Animal {
            public:
                template< class AMOUNT >
                void eat( AMOUNT amount) const { 
                    std::cout << "I eat like a fish!" << std::endl; 
                }
                virtual ~Fish() { 
                }
        };

        class GoldFish : public Fish {
            public:
                template< class AMOUNT >
                void eat( AMOUNT amount) const { 
                    std::cout << "I eat like a goldfish!" << std::endl; 
                }
                virtual ~GoldFish() { 
                }
        };

        class OtherAnimal : public Animal {
                //OtherAnimal constructors must be defined here as Animal's constructors
                OtherAnimal(const Animal& a) : Animal(a) {}
                OtherAnimal(const Wolf& w) : Animal(w) {}
                OtherAnimal(const Fish& f) : Animal(f) {}
                OtherAnimal(const GoldFish& g) : Animal(g) {}
                OtherAnimal(const OtherAnimal& o) : Animal(o) {}
                virtual ~OtherAnimal() { 
                }
        };
        //OtherAnimal will be useful only if it has it's own actions and members, because if not, typedef Animal OtherAnimal or using OtherAnimal = Animal can be used, and it can be removed from above declarations and below definitions

//Here are the definitions of Animal constructors that were declared above/before:    
        Animal::Animal(const Animal& a) : who_really_am_I(AnimalEnum::animal), animal_ptr(nullptr) {}

        Animal::Animal(const Wolf& w) : who_really_am_I(AnimalEnum::wolf), animal_ptr(new Wolf(w)) {}

        Animal::Animal(const Fish& f) : who_really_am_I(AnimalEnum::fish), animal_ptr(new Fish(f)) {}

        Animal::Animal(const GoldFish& g) : who_really_am_I(AnimalEnum::goldfish), animal_ptr(new GoldFish(g)) {}

        Animal::Animal(const OtherAnimal& o) :
    who_really_am_I(AnimalEnum::other), animal_ptr(new OtherAnimal(o)) {}

        int main() {
            std::vector<Animal> animals;
            animals.push_back(Animal());
            animals.push_back(Wolf()); //Wolf is converted to Animal via constructor
            animals.push_back(Fish()); //Fish is converted to Animal via constructor
            animals.push_back(GoldFish()); //GoldFish is converted to Animal via constructor
            animals.push_back(OtherAnimal()); //OtherAnimal is converted to Animal via constructor

            for (std::vector<Animal>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
                it->eat(); //this is Animal's eat that invokes other animals eat
                //delete *it; Now it should be:
                it->DeleteMemory();
            }
            animals.clear(); //All animals have been killed, and we don't want full vector of dead animals.

            return 0;
        }
Chacon answered 4/8, 2016 at 22:10 Comment(1)
virtual is inherited, so fish should have ~Fish() override = default; insteadTrine
S
0

In you scenario, you are trying to mix compile time polymorphism with runtime polymorphism, but it cannot be done in this "direction".

Essential, your AMOUNT template argument represents an expected interface for the type to implement based on the union of all the operations each implementation of eat uses. If you where to create an abstract type that declared each of those operations making them virtual where needed, then you could call eat with different types (that derived from your AMOUNT interface). And it would behave as expected.

Sharpe answered 4/8, 2016 at 22:30 Comment(0)
M
-8

I don't work with templates, but I think:

(1) You cannot use templates inside a class, templates are more like global types or global variables.

(2) In O.O.P., the same problem you present, and that you are trying to solve by using templates, can be solved by using inheritance.

Classes work similar to templates, you can extended by adding new things, or replace things of classes with pointers, pointers to objects (A.K.A. "references") and overriding virtual functions.

#include <iostream>

struct Animal {
    virtual void eat(int amount ) {
        std::cout << "I eat like a generic Animal." << std::endl;
    }
    virtual ~Animal() { }
};

#if 0

// example 1
struct Wolf : Animal {
    virtual void eat(int amount) {
        std::cout << "I eat like a wolf!" << std::endl;
    }
};

struct Fish : Animal {
    virtual void eat(int amount) {
        std::cout << "I eat like a fish!" << std::endl;
    }
};

#else

// example 2

struct AnimalFood {
    virtual int readAmount() { return 5; }

    virtual void showName() {
        std::cout << "I'm generic animal food" << std::endl;
    }
};

struct PredatorFood : AnimalFood {
    virtual int readAmount() { return 500; }

    virtual void showName() {
        std::cout << "I'm food for a predator" << std::endl;
    }
};


struct Fish : Animal {
    virtual void eat(AnimalFood* aFood) {
        if (aFood->readAmount() < 50) {
            std::cout << "OK food, vitamines: " << aFood->readAmount() << std::endl;
        } else {
            std::cout << "too much food, vitamines: " << aFood->readAmount() << std::endl;
        }
    }
};

struct Shark : Fish {
    virtual void eat(AnimalFood* aFood) {
        if (aFood->readAmount() < 250) {
            std::cout << "too litle food for a shark, Im very hungry, vitamines: " << aFood->readAmount() << std::endl;
        } else {
            std::cout << "OK, vitamines: " << aFood->readAmount() << std::endl;
        }
    }
};

struct Wolf : Fish {
    virtual void eat(AnimalFood* aFood) {
        if (aFood->readAmount() < 150) {
            std::cout << "too litle food for a wolf, Im very hungry, vitamines: " << aFood->readAmount() << std::endl;
        } else {
            std::cout << "OK, vitamines: " << aFood->readAmount() << std::endl;
        }
    }
};

#endif

int main() {
    // find animals
    Wolf* loneWolf = new Wolf();
    Fish* goldenFish = new Fish();
    Shark* sharky = new Shark();

    // prepare food
    AnimalFood* genericFood = new AnimalFood();
    PredatorFood* bigAnimalFood = new PredatorFood();

    // give food to animals
    loneWolf->eat(genericFood);
    loneWolf->eat(bigAnimalFood);

    goldenFish->eat(genericFood);
    goldenFish->eat(bigAnimalFood);

    sharky->eat(genericFood);
    sharky->eat(bigAnimalFood);

    delete bigAnimalFood;
    delete genericFood;

    delete sharky;
    delete goldenFish;
    delete loneWolf;
}

Cheers.

Meander answered 3/5, 2011 at 15:39 Comment(10)
Double underscores are reserved for the implementation in all cases, and due to various rules I suggest avoiding leading underscores completely as well.Vipul
(1) is incorrect -- you can have template methods inside of a class.Noe
@Mark B Good Observation. But, double underscores are also used for "pseudokeywords", words that are treated as keywords by an specific compilers / linkers. "Override" is used as a keyword in some compilers, and some not, I think last version C++ standard mark as a keyword, and underscore not need it anymore.Meander
The C++ standard explicitly and clearly forbids the use of any name that starts with one or two underscore characters (sections 17.4.3.1.2/1 and 17.4.3.1.3/3). These are reserved for the compiler vendors for internal use (and non-standard extensions). If you want to write code that has even a remote chance of being portable between different compilers, you have to avoid using those names completely, even if it happens to work on your compiler or a few that you tested.Dunghill
And the reason compilers use double underscores in extensions is specifically because C++ code isn't allowed to contain them. There is no risk of stomping on existing code. Also, I don't believe override ended up a keyword in 0x; it might be listed an attribute, but those aren't used the way you have here.Conversable
I appreciate all positive and negative comments, but regret no answer about the way I suggest to answer the main question :-sMeander
@Meander Ok, substantial comment then: I revised your code so it now compiles (ideone.com/6zJJp). I don't really see the added value, perhaps you were misled by the not-so-very-well-chosen sample from the question?Atal
@Atal My code example has been edited several times from others that already misses the original point :-sMeander
@umlcat: That is simply not true (see change history). Do you think my edits made it worse? You can always rollback it (in which case I might have to downvote it...)Atal
It's not always possible to easily replace static polymorphism with dynamic polymorphism because dynamic polymorphism doesn't participate in overload resolution.Bifocals

© 2022 - 2024 — McMap. All rights reserved.