继承,选择性方法执行

Inheritance, selective method execution

本文关键字:执行 方法 选择性 继承      更新时间:2023-10-16

我看了一个视频,可以在https://www.youtube.com/watch?v=4F72VULWFvc,我真的很喜欢其中一些案例的概念。但是我正在使用链表,需要选择方法执行,例如:

#include <stdio.h>
class A {
 public:
    A() : next(0) {
        if (head == 0) {
            head = this;
        } else {
            A* step = head;
            while (step->next != 0) {
                step = step->next;
            }
            step->next = this;
        }
    }
    virtual ~A() {
        if (head == this) {
            head = 0;
        } else {
            A* step = head;
            while (step->next != this) {
                step = step->next;
            }
            step->next = next;
        }
    }
    virtual void foo() {
        // Do nothing...
    }
    static A* head;
    A* next;
};
class B : public A {
 public:
    B() {}
    virtual ~B() {}
    virtual void foo() {
        printf("function foon");
    }
};
A* A::head = 0;
int main() {
    A a_cls;
    B b_cls;
    A* step = A::head;
    while (step != 0) {
        step->foo();
        step = step->next;
    }
    return 0;
}

实例化所有对象后,需要执行B类对象的方法foo()。为此,在A类中添加虚方法foo(),空方法体virtual void foo() {};在B类中,在foo()方法体中添加代码。

它工作,但我不喜欢它,在主函数中,它看起来像你在每个节点做一些事情,但你不是,它几乎感觉像一个空指针。是否有其他创造性的解决方案?

注意:我使用的是c++ 03.

查看dynamic_cast作为检查特定派生类型的方法,并且只在类B(或从B派生的类)的对象上调用foo:

int main() {
    A a_cls;
    B b_cls;
    A* step = A::head;
    B* step_b = 0;
    while (step != 0) {
        step_b = dynamic_cast<B *>(step);
        if (step_b != 0) {
            step_b->foo();
        }
        step = step->next;
    }
    return 0;
}
这样,就不需要在A上定义一个空的foo方法。在ideone上试试。

它工作,但我不喜欢它,在主要功能,它看起来像你在每个节点做一些事情,但你没有

实际上你在每个节点上都做了一些。你所做的就是决定什么都不做。决策通常不是自由的,您还没有告诉我们足够的应用程序信息,以证明可以以一种决策可以有效自由(在编译时做出)的方式进行重构的猜测是正确的。

如果什么都不做的决定不可能是自由的,那么将该决定作为对虚函数的调用来实现几乎是该决定可能的最低成本。

它工作,但我不喜欢它,在main函数看起来像你在每个节点做的事情,但你不是,它几乎感觉像一个NULL指针。是否有其他创造性的解决方案?

确保你的基类是一个纯抽象类。这样,每次调用step->foo();都很可能会做一些事情。

这是一个异构列表的基本示例。List::Node是一个抽象基类。List::Node::print()是一个虚成员函数,只在具体类中实现。List可以使用一个泛型算法来遍历Node s,而不需要明确知道它所包含的Node s的种类。

#include <iostream>
#include <string>
class List
{
   public:
      class Node
      {
         public:
            Node() : next(nullptr) {}
            virtual ~Node() {}
            virtual void print() = 0;
            Node* next;
      };
      List() : head(nullptr), tail(nullptr) {}
      ~List()
      {
         Node* node = head;
         Node* next = nullptr;
         for ( ; node != nullptr; node = next )
         {
            next = node->next;
            delete node;
         }
      }
      void addNode(Node* node)
      {
        if (head == 0)
        {
            head = tail = node;
            return;
        }
        if ( head == tail )
        {
           head->next = node;
        }
        tail->next = node;
        tail = node;
      }
      void print()
      {
         Node* node = head;
         for ( ; node != nullptr; node = node->next )
         {
            node->print();
            std::cout << std::endl;
         }
      }
      Node* head;
      Node* tail;
};
class NodeA : public List::Node
{
   public:
      NodeA(int d) : data(d) {}
      virtual ~NodeA() {}
      virtual void print()
      {
         std::cout << "In NodeA::print(), Data: " << data;
      }
   private:
      int data;
};

class NodeB : public List::Node
{
   public:
      NodeB(double d) : data(d) {}
      virtual ~NodeB() {}
      virtual void print()
      {
         std::cout << "In NodeB::print(), Data: " << data;
      }
   private:
      double data;
};

class NodeC : public List::Node
{
   public:
      NodeC(std::string const& d) : data(d) {}
      virtual ~NodeC() {}
      virtual void print()
      {
         std::cout << "In NodeC::print(), Data: " << data;
      }
   private:
      std::string data;
};
int main()
{
   List list;
   list.addNode(new NodeA(10));
   list.addNode(new NodeB(23.45));
   list.addNode(new NodeC("abcd"));
   list.print();
   return 0;
}

尽管Austin的解决方案非常好,但在这种情况下,另一种方法(我通常更喜欢)是使用接口类和上转换。

class FooFighter { public: virtual void foo() = 0; };
class A { ... };
class B1 : public A { ... };
class B2 : public A, public FooFighter { ... };
...
int main() {
  std::vector<A *> v;
  // fill up v
  for (int i = 0; i < v.size(); ++i) {
    FooFighter * ff = dynamic_cast<FooFighter *>(v[i]);
    if (ff) ff.foo();
  }
  return 0;

}

这让你保持一个类是否有足够独立于你的层次结构的其余部分。特别是,通过检查任何类型的类层次结构,你总是知道该类型是否实现了foo,因为它必须继承自FooFighter。当您使用向下转换方法时,您可以有A的多个子节点,它们以不同的方式非平凡地实现foo。这种方法还可以很好地配合ide,让您可以轻松地检查和遍历代码中的类型层次结构。