How to achieve “virtual template function” in C++

后端 未结 9 1676
囚心锁ツ
囚心锁ツ 2020-11-28 03:20

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

9条回答
  •  伪装坚强ぢ
    2020-11-28 04:15

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

            #include 
            #include 
    
            //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 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::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;
            }
    

提交回复
热议问题