C++ 具有扩展接口的派生类的集合。如何在没有动态强制转换的情况下访问派生接口?

C++ 具有扩展接口的派生类的集合。如何在没有动态强制转换的情况下访问派生接口?,c++,oop,C++,Oop,假设我有一个“动物”类型的抽象对象。动物有公纯虚法“吃” 我想将动物派生为“狗”和“猫”,每个都有一个扩展接口。例如,我希望狗有一个公共方法“chaseTail”,猫有一个公共方法“destroyFurniture” 我想制作一个“世界”对象中的动物集合 我需要能够使用“GetAnimalPosition”方法从世界上检索这些动物,并且能够任意调用chaseTail或销毁我得到的动物上的家具 我想避免缓慢的动态施法,测试位置是否是给定的动物,或是将追逐的尾巴和家具提升到动物身上,但我似乎回到了一

假设我有一个“动物”类型的抽象对象。动物有公纯虚法“吃”

我想将动物派生为“狗”和“猫”,每个都有一个扩展接口。例如,我希望狗有一个公共方法“chaseTail”,猫有一个公共方法“destroyFurniture”

我想制作一个“世界”对象中的动物集合

我需要能够使用“GetAnimalPosition”方法从世界上检索这些动物,并且能够任意调用chaseTail或销毁我得到的动物上的家具

我想避免缓慢的动态施法,测试位置是否是给定的动物,或是将追逐的尾巴和家具提升到动物身上,但我似乎回到了一个角落


还有其他方法吗?

您可以在完全了解所有类的情况下执行访问者模式操作。

您可以在完全了解所有类的情况下执行访问者模式操作。

希望在运行时发现多态层次结构的动态类型通常表明存在设计错误。您可以尝试以下方法:

struct Animal
{
    virtual ~Animal()             {              }
    void eat()                    { doEat();     }
    void performTypicalActivity() { doTypical(); }
private:
    virtual void doEat() = 0;
    virtual void doTypical() = 0;
};

struct Cat : Animal
{
    void destroyFurniture();
    void purr();
private:
    virtual void doTypical() { destroyFurniture(); purr(); }
};

现在,您在集合上迭代,并对每个元素调用
p->performTypicalActivity()

在运行时发现多态层次结构的动态类型通常表明存在设计错误。您可以尝试以下方法:

struct Animal
{
    virtual ~Animal()             {              }
    void eat()                    { doEat();     }
    void performTypicalActivity() { doTypical(); }
private:
    virtual void doEat() = 0;
    virtual void doTypical() = 0;
};

struct Cat : Animal
{
    void destroyFurniture();
    void purr();
private:
    virtual void doTypical() { destroyFurniture(); purr(); }
};
现在,您迭代您的集合,并对每个元素调用
p->performTypicalActivity()

是一个可行的解决方案。该解决方案有两个主要参与者:

  • 元素:具有接受访问者的公共父级的不同类型。在这种情况下,元素是
    Cat
    Dog
    ,共同的父元素是
    Animal
  • Visitor:将访问元素的类,可以调用特定于元素的操作,因为它具有特定元素类型的句柄
对于本例,从元素(动物、猫和狗)开始:

接下来,创建一个将“访问”每个元素的访问者。访问者将知道它正在操作的类型,因此可以在特定元素上使用方法,例如
Cat::destrofurniture()
Dog::chaseTail()

现在,向
Animal
添加一个纯虚拟方法,该方法接受
Visitor
作为参数:
void Animal::accept(Vistor&)
。其思想是将
访问者
传递给
动物
,并允许虚拟方法解析为特定的运行时类型。一旦虚拟调用被解析,实现就可以调用
Visitor
上的特定
visit
方法

class Animal
{
public:
  ...
  virtual void accept( Visitor& ) = 0;
};

class Cat: public Animal
{
public:
  ...
  virtual void accept( Visitor& visitor ) { visitor.visitCat( *this ); }
};
class Visitor
{
public:
   virtual void visitCat( Cat& ) = 0;
   virtual void visitDog( Dog& ) = 0; 
};

class FurnitureDestroyingVisitor: public Visitor
{
   virtual void visitCat( Cat& cat ) { cat.destroyFurniture(); }
   virtual void visitDog( Dog& dog ) {} // Dogs cannot destroy furniture.
};
注意虚拟方法如何用于解析特定的元素类型,以及每个元素的
accept
实现将调用访问者上的方法。这允许执行基于类型的分支,而无需使用
dynamic\u cast
,通常称为


是一个可编译的示例,演示了正在使用的模式:

#include <iostream>
#include <vector>

using std::cout;
using std::endl;

class Cat;
class Dog;

class Visitor
{
public:
   void visitCat( Cat& cat );
   void visitDog( Dog& dog );
};

class Animal
{
public:
  virtual ~Animal() {}
  virtual void eat() = 0;
  virtual void accept( Visitor& ) = 0;
};

class Cat: public Animal
{
public:
  void destroyFurniture()         { cout << "Cat::destroyFurniture()" << endl; }
  void eat()                      { cout << "Cat::eat()" << endl;              }  
  void accept( Visitor& visitor ) { visitor.visitCat( *this );                 }
};

class Dog: public Animal
{
public:
  void chaseTail()                { cout << "Dog::chaseTail()" << endl; }
  void eat()                      { cout << "Dog::eat()" << endl;       }  
  void accept( Visitor& visitor ) { visitor.visitDog( *this );          }
};

// Define Visitor::visit methods.
void Visitor::visitCat( Cat& cat ) { cat.destroyFurniture(); }
void Visitor::visitDog( Dog& dog ) { dog.chaseTail();        }

int main()
{
  typedef std::vector< Animal* > Animals;
  Animals animals;
  animals.push_back( new Cat() );
  animals.push_back( new Dog() );

  Visitor visitor;  
  for ( Animals::iterator iterator = animals.begin();
        iterator != animals.end(); ++iterator )
  {
    Animal* animal = *iterator;
    // Perform operation on base class.
    animal->eat();
    // Perform specific operation based on concrete class.
    animal->accept( visitor );
  }

  return 0;
}

请注意,在本例中,
Visitor
是一个具体的类。但是,可以为
访问者
创建整个层次结构,允许您根据
访问者
执行不同的操作

class Animal
{
public:
  ...
  virtual void accept( Visitor& ) = 0;
};

class Cat: public Animal
{
public:
  ...
  virtual void accept( Visitor& visitor ) { visitor.visitCat( *this ); }
};
class Visitor
{
public:
   virtual void visitCat( Cat& ) = 0;
   virtual void visitDog( Dog& ) = 0; 
};

class FurnitureDestroyingVisitor: public Visitor
{
   virtual void visitCat( Cat& cat ) { cat.destroyFurniture(); }
   virtual void visitDog( Dog& dog ) {} // Dogs cannot destroy furniture.
};
访问者模式的一个主要缺点是添加
元素
可能需要更改
访问者
类。一般的经验法则是:

  • 如果元素层次结构可能会更改,那么在基本元素类上定义操作可能会更容易。在本例中,如果需要添加
    奶牛
    ,则可能更容易向
    动物
    添加虚拟
    点典型
    方法
  • 如果元素层次结构是稳定的,但是操作元素的算法在变化,那么访问者模式可能是一个很好的候选者
    • 这是一个可行的解决方案。该解决方案有两个主要参与者:

      • 元素:具有接受访问者的公共父级的不同类型。在这种情况下,元素是
        Cat
        Dog
        ,共同的父元素是
        Animal
      • Visitor:将访问元素的类,可以调用特定于元素的操作,因为它具有特定元素类型的句柄
      对于本例,从元素(动物、猫和狗)开始:

      接下来,创建一个将“访问”每个元素的访问者。访问者将知道它正在操作的类型,因此可以在特定元素上使用方法,例如
      Cat::destrofurniture()
      Dog::chaseTail()

      现在,向
      Animal
      添加一个纯虚拟方法,该方法接受
      Visitor
      作为参数:
      void Animal::accept(Vistor&)
      。其思想是将
      访问者
      传递给
      动物
      ,并允许虚拟方法解析为特定的运行时类型。一旦虚拟调用被解析,实现就可以调用
      Visitor
      上的特定
      visit
      方法

      class Animal
      {
      public:
        ...
        virtual void accept( Visitor& ) = 0;
      };
      
      class Cat: public Animal
      {
      public:
        ...
        virtual void accept( Visitor& visitor ) { visitor.visitCat( *this ); }
      };
      
      class Visitor
      {
      public:
         virtual void visitCat( Cat& ) = 0;
         virtual void visitDog( Dog& ) = 0; 
      };
      
      class FurnitureDestroyingVisitor: public Visitor
      {
         virtual void visitCat( Cat& cat ) { cat.destroyFurniture(); }
         virtual void visitDog( Dog& dog ) {} // Dogs cannot destroy furniture.
      };
      
      注意虚拟方法如何用于解析特定的元素类型,以及每个元素的
      accept
      实现将调用访问者上的方法。这允许执行基于类型的分支,而无需使用
      dynamic\u cast
      ,通常称为


      是一个可编译的示例,演示了正在使用的模式:

      #include <iostream>
      #include <vector>
      
      using std::cout;
      using std::endl;
      
      class Cat;
      class Dog;
      
      class Visitor
      {
      public:
         void visitCat( Cat& cat );
         void visitDog( Dog& dog );
      };
      
      class Animal
      {
      public:
        virtual ~Animal() {}
        virtual void eat() = 0;
        virtual void accept( Visitor& ) = 0;
      };
      
      class Cat: public Animal
      {
      public:
        void destroyFurniture()         { cout << "Cat::destroyFurniture()" << endl; }
        void eat()                      { cout << "Cat::eat()" << endl;              }  
        void accept( Visitor& visitor ) { visitor.visitCat( *this );                 }
      };
      
      class Dog: public Animal
      {
      public:
        void chaseTail()                { cout << "Dog::chaseTail()" << endl; }
        void eat()                      { cout << "Dog::eat()" << endl;       }  
        void accept( Visitor& visitor ) { visitor.visitDog( *this );          }
      };
      
      // Define Visitor::visit methods.
      void Visitor::visitCat( Cat& cat ) { cat.destroyFurniture(); }
      void Visitor::visitDog( Dog& dog ) { dog.chaseTail();        }
      
      int main()
      {
        typedef std::vector< Animal* > Animals;
        Animals animals;
        animals.push_back( new Cat() );
        animals.push_back( new Dog() );
      
        Visitor visitor;  
        for ( Animals::iterator iterator = animals.begin();
              iterator != animals.end(); ++iterator )
        {
          Animal* animal = *iterator;
          // Perform operation on base class.
          animal->eat();
          // Perform specific operation based on concrete class.
          animal->accept( visitor );
        }
      
        return 0;
      }
      

      请注意,在本例中,
      Visitor
      是一个具体的类。但是,可以为
      访问者
      创建整个层次结构,允许您根据
      访问者
      执行不同的操作

      class Animal
      {
      public:
        ...
        virtual void accept( Visitor& ) = 0;
      };
      
      class Cat: public Animal
      {
      public:
        ...
        virtual void accept( Visitor& visitor ) { visitor.visitCat( *this ); }
      };
      
      class Visitor
      {
      public:
         virtual void visitCat( Cat& ) = 0;
         virtual void visitDog( Dog& ) = 0; 
      };
      
      class FurnitureDestroyingVisitor: public Visitor
      {
         virtual void visitCat( Cat& cat ) { cat.destroyFurniture(); }
         virtual void visitDog( Dog& dog ) {} // Dogs cannot destroy furniture.
      };
      
      访问者模式的一个主要缺点是添加
      El