如何创建一个带有基类和派生类的函数的专用和默认版本?

时间:2015-05-20 22:39:33

标签: c++ templates inheritance

我有以下类架构:

Bar

在我的代码的另一部分中,我有一个函数,它遍历一个动物列表,并且需要在几个派生类的情况下执行特殊操作,否则需要执行默认操作。考虑到以下限制,我如何优雅地处理这种情况:

  1. 我想将新代码保留在Animal及其派生之外 由于关注点分离而导致的课程。
  2. 我想避免在类型或枚举上使用switch语句,因为它感觉很臭。

2 个答案:

答案 0 :(得分:3)

这是一种方式 - 使用概念模型习语(我的名字):

IEnumerable<Program> records = reader.GetRecords<Program>().Where(r => r.Age >= 62).ToList();

writer.WriteRecords(records);

// No futher code

预期产出:

#include <iostream>
#include <vector>

struct AnimalConcept {
    virtual ~AnimalConcept() = default;

    virtual void make_noise() const = 0;
};

// default case
void make_noise_for(const AnimalConcept&)
{
    std::cout << "no noise" << std::endl;
}

template<class Model>
struct AnimalModel : AnimalConcept
{

    void make_noise() const override {
        make_noise_for(static_cast<const Model&>(*this));
    }
};

// some models

struct Cat : AnimalModel<Cat>
{

};

struct Dog : AnimalModel<Dog>
{

};

struct Giraffe : AnimalModel<Giraffe>
{

};

// separation of concerns - specific overrides

void make_noise_for(const Cat&) {
    std::cout << "meow\n";
}

void make_noise_for(const Dog&) {
    std::cout << "woof\n";
}

// test

using namespace std;

int main(){
    std::vector<std::unique_ptr<const AnimalConcept>> animals;
    animals.emplace_back(new Cat);
    animals.emplace_back(new Dog);
    animals.emplace_back(new Giraffe);

    for (const auto& p : animals) {
        p->make_noise();
    }

    return 0;
}

这是实现它的另一种方式(这个更好,因为它允许所有动物拥有不相关的接口):

meow
woof
no noise

预期产出:

#include <iostream>
#include <vector>

struct AnimalConcept {
    virtual ~AnimalConcept() = default;

    virtual void make_noise() const = 0;
};

// default case
template<class T>
void make_noise_for(const T&)
{
    std::cout << "this animal makes no noise" << std::endl;
}

template<class Model>
struct AnimalModel : AnimalConcept
{
    template<class...Args>
    AnimalModel(Args&&...args)
    : _model { std::forward<Args>(args)... }
    {}

private:
    void make_noise() const override {
        make_noise_for(_model);
    }

    Model _model;
};

// some models

struct Cat
{
    Cat(std::string name)
    : _name { std::move(name) }
    {}

    const std::string& name() const {
        return _name;
    }

private:
    std::string _name;
};

struct Dog
{
    Dog(std::string name, int age)
    : _name { std::move(name) }
    , _age { age }
    {}

    const std::string& name() const {
        return _name;
    }

    int age() const {
        return _age;
    }

private:
    std::string _name;
    int _age;
};

struct Giraffe
{

};

// separation of concerns - specific overrides

void make_noise_for(const Cat& c) {
    std::cout << c.name() << " says meow\n";
}

void make_noise_for(const Dog& d) {
    std::cout << "the dog called " << d.name() << " who is " << d.age() << " years old says woof\n";
}

// test

using namespace std;

int main(){
    std::vector<std::unique_ptr<const AnimalConcept>> animals;
    animals.emplace_back(new AnimalModel<Cat> { "felix" });
    animals.emplace_back(new AnimalModel<Dog> { "fido", 2 });
    animals.emplace_back(new AnimalModel<Giraffe>);

    for (const auto& p : animals) {
        p->make_noise();
    }

    return 0;
}

答案 1 :(得分:0)

您可以使用以下组合来获取基于类型的调度。

  1. 为每个类提供返回与之关联的类型ID。
  2. 在基类中提供虚函数以获取与对象关联的类型ID。
  3. 提供基于类型ID注册功能的方法。
  4. 当执行顶级功能时,在给定动物类型ID的情况下搜索已注册的功能。如果注册了某个功能,请将其调用。否则,请使用默认功能。
  5. // Implement this function in a .cpp file.
    int getNextTypeID()
    {
       static int typeID = 0;
       return ++typeID;
    }
    
    class Animal 
    {
       virtual int getTypeID();
    };
    
    class Cat : public Animal
    {
       static int getID()
       {
          static int typeID = getNextTypeID();
       }
    
       virtual int getTypeID()
       {
          return getID();
       }
    };
    
    class Dog : public Animal
    {
       static int getID()
       {
          static int typeID = getNextTypeID();
       }
    
       virtual int getTypeID()
       {
          return getID();
       }
    };
    

    foo.h中:

    typedef void (*AnimalFunction)(Animal& a);
    
    int registerAnimalFunctor(int typeID, AnimalFunction f);
    
    void foo(Animal& a);
    

    Foo.cpp中:

    typedef std::map<int, AnimalFunction> AnimalFunctionMap;
    
    AnimalFunctionMap& getAnimalFunctionMap()
    {
       static AnimalFunctionMap theMap;
       return theMap;
    }
    
    int registerAnimalFunctor(int typeID, AnimalFunction f)
    {
       getAnimalFunctionMap()[typeID] = f;
       return 0;
    }
    
    void defaultAnimalFunction(a)
    {
       // Default action
    }
    
    void foo(Animal& a)
    {
       AnimalFunctionMap& theMap = getAnimalFunctionMap();
       AnimalFunctionMap::iterator iter = theMap.find(a.getTypeID());
       if ( iter != theMap.end() )
       {
          iter->second(a);
       }
       else
       {
          defaultAnimalFunction(a);
       }
    }
    

    cat_foo.cpp:

    void CatFunction(Animal& a)
    {
       // Cat action.
    }
    
    int dummy = registerAnimalFunctor(Cat::getID(), CatFunction);
    

    dog_foo.cpp:

    void DogFunction(Animal& a)
    {
       // Dog action.
    }
    
    int dummy = registerAnimalFunctor(Dog::getID(), DogFunction);