【问题标题】:Looping through the derived classes by referencing the base class in C++通过在 C++ 中引用基类来循环遍历派生类
【发布时间】:2013-06-26 11:54:35
【问题描述】:

对不起,如果之前有人问过这个问题,刚学C++,曾尝试搜索但不知道关键字是什么。

可以这样做吗?

class Car {
   public:
      void addColor(string c) {
          color = c;
      }

   private:
      string color;
}

class Honda:public Car {}
class Toyota:public Car {}

int main() {
    vector<Car> v;

    Honda *car1 = new Honda();
    car1.addColor("green");

    Toyota *car2 = new Toyota();
    car2.addColor("blue");

    v.push_back(car1);
    v.push_back(car2);

    for (int i = 0; i < v.size(); i++) {
        cout << v[i].color << endl; // should output green, blue
    }

}

如果可能,最正确/最有效的方法是什么?

编辑 1

哇,谢谢大家!

【问题讨论】:

  • 简短:是的。如果您可以使用接口函数处理所有事情,那就没问题了。如果您只需要一个派生类中的一个函数,您很可能需要 RTTI(在 foreach 循环中向下转换)
  • 一方面,颜色是一个私有变量。您将通过其他方式获得价值
  • 您将需要一个容器来保存指向Car 的(智能)指针,而不是您现在拥有的Car 对象。
  • @juanchopanza 在这里绝对不需要智能指针!
  • @Jerska 对,new 也不是。

标签: c++


【解决方案1】:

你的向量总是保持基本类型,汽车,切片。查找“多态 STL 集合”“多态向量”或想了解如何存储派生类。

here 是一个例子

【讨论】:

    【解决方案2】:

    有两种方法可以处理这个问题。假设我们有以下类定义:

    #include <string>
    class Car {
       public:
          Car(const std::string& color) : color(color) {}
          virtual ~Car() {}
    
          std::string color;
    };
    
    class Honda:public Car {};
    class Toyota:public Car {};
    

    请注意,我删除了 setter,只是将成员公开。你可能想要也可能不想要这个,但对于这个例子来说,这并不重要。 这是一种分配堆栈上的所有内容并获取这些对象的地址的方法。在本例中这很好(car1car2 不需要比 main 函数寿命更长)。在实际代码中,这可能不是真的(即对象可能需要比创建它们的函数寿命更长,请参见下文):

    #include <iostream>
    #include <vector>
    
    int main() {
        Honda car1("green");
        Toyota car2("blue");
        std::vector<Car*> cars; // vector of non-owning pointers
    
        v.push_back(&car1);
        v.push_back(&car2);
    
        for(auto& car : cars) {
            std::cout << car.color << "\n";
        }
    }
    

    或者,在堆上分配您的对象:

    int main() {
        std::vector<std::unique_ptr<Car>> cars; // vector of owning pointers
    
        v.emplace_back(new Honda("green"));
        v.push_back(new Toyota("blue"));
    
        for(auto& carptr : cars) {
            std::cout << carptr->color << "\n";
        }
    }
    

    【讨论】:

    【解决方案3】:

    您的方法是正确的,只是需要解决一些小问题:

    • 向基类添加getter (Car);
    • 更改矢量类型(为vector&lt;Car*&gt;);
    • 在需要时将a.b 替换为a-&gt;b
    • 修复类定义后缺少的分号。

    给你:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class Car {
       public:
          virtual ~Car ();
          void addColor(string c) {
              color = c;
          }
    
          string getColor () {
              return color;
          }
    
       private:
          string color;
    };
    
    class Honda:public Car {};
    class Toyota:public Car {};
    
    int main() {
        vector<Car*> v;
    
        Honda car1;
        car1.addColor("green");
    
        Toyota car2;
        car2.addColor("blue");
    
        v.push_back(&car1);
        v.push_back(&car2);
    
        for (int i = 0; i < v.size(); i++) {
            cout << v[i]->getColor () << endl; // should output green, blue
        }
    }
    

    顺便说一句,如果你想让你的子类有自己的方法来操纵颜色,只需在汽车类中将方法声明为virtual,你可以在子类中重新定义它。

    另一个小点。你不能让你的向量成为vector&lt;Car&gt;。因为子类的大小可能与母类的大小不同(想象一下在您的Honda 类中添加一个int appeal;),因为向量只能存储大小相同的元素。

    【讨论】:

    • 这会泄漏内存。在 C++11 中,将其设为 vector>.
    • 即使为car1car2 添加deletes,仍然会泄漏内存;没有虚拟析构函数。
    • 您对泄漏是认真的吗?该操作询问有关如何动态调用方法的解释,而您正在争论如何避免泄漏的最佳方法?
    • @Jerska:是的。代码需要正确。为此,你有我的反对意见(除其他外)。
    • @BalogPal 最初都是动态分配的没有被销毁的对象。不是给新人树立的好榜样。
    猜你喜欢
    • 2020-04-25
    • 1970-01-01
    • 2021-12-05
    • 2018-06-28
    • 2011-03-23
    • 2014-10-29
    • 1970-01-01
    • 2019-06-02
    • 2010-10-21
    相关资源
    最近更新 更多