指向派生对象的基类指针的 C++ 排序容器

Posted

技术标签:

【中文标题】指向派生对象的基类指针的 C++ 排序容器【英文标题】:C++ sorting container of base class pointers to derived objects 【发布时间】:2015-08-17 19:56:37 【问题描述】:

我有一个基类指针的 std::list,所有这些指针都指向两个派生对象类之一。基类的实例永远不会被声明,尽管基类不是抽象的,但每个成员函数都被声明为虚拟的。考虑下面的代码:

class A

public:
    A();
    ...
    //member functions
    ...

protected:
    int common_data_1;
    std::string common_data_2;
    ...
;

class B: public A

public:
    B();
    //member functions
    ...

protected:
    std::string class_B_specific_data;
    ...
;

class C: public A

public:
    C();
    //member functions
    ...

protected:
    std::string class_C_specific_data;
    ...
;

这些类通过条件语句被实例化为适当的基类,并通过基类指针同时存储在 std::list 中的同一代码块中,如下所示:

std::list<A*> ptrList;

//conditional statements either create a B or C object
//and then that object is appended to the list

if (blahblah = true)
    A* entry = new B();
else
    A* entry = new C();

ptrList.append(entry);

我需要基于两个派生类都继承的整数值对这个基类指针容器执行插入排序;然而,在我之前的尝试和使用调试器工具检查时,我发现我的插入排序算法在访问比较所基于的整数时正确地进行了正确的比较,但是我无法交换std::list 中的基类指针。我想对这个指针容器进行排序,以便我可以使用简单的 for 循环以正确的顺序轻松打印数据。

这显然是对指针语义误解的结果,但我一直无法找到任何参考或示例来阐明或解决我遇到的问题。

我在此站点或其他地方找到的任何结果都通过使用实际对象的容器而不是指向对象的指针容器来解决此问题。但是,就我而言,我不能这样做,因为我的代码依赖于基类的多态行为,以便拥有一个大的派生对象列表,而不是每个派生对象的多个列表。显然,这使得调用正确派生类的成员函数变得非常容易,如果可以避免的话,我宁愿不重新设计数据的整个结构。

如果需要,我可以发布我的代码的 sn-ps 和/或我为正确交换容器内的这些指针位置所做的尝试;但是,我不确定这是否会有所帮助,因为我显然使用了错误的语法来处理指针。

感谢任何反馈;在过去的几周里,这个问题一直困扰着我,现在绝对是我退后一步寻求帮助的时候了。我感觉我过度分析了这个问题,这很可能是阻碍我解决问题的原因。

【问题讨论】:

是需要对容器进行插入排序,还是需要对容器进行排序? 停止使用std::list。不完全是。这几乎从来都不是一个好主意。其次,请提供导致问题的实际代码——在这种情况下,调用std::sort,以及变量的类型。理想情况下是 SSCCE —— 一段实际的代码,用于演示出错的地方,而不是包含您认为重要内容的伪代码;如果你明白什么是重要的,你就不会寻求帮助。但是,你可以简化你的代码,测试它仍然会产生问题,然后重复直到你的代码很短,而不知道什么是重要的(因为你可以测试)。 显示实际显示问题的代码是个好主意。 正如其他人所指出的,目前尚不清楚您要做什么以及问题出在哪里,但是,话虽如此,使用带有 lambda 表达式的 std::list::sort() 作为参数是我的首选方式对指针集合进行排序,其中您使用指向对象的某些数据成员作为排序标准。 您说您无法交换列表中的元素;如果是这种情况,那么您肯定做错了什么,我建议您清除这一点,无论您是否有一个工作的分拣机。 【参考方案1】:

假设您的目标是对现有容器进行排序,sort 有一个 Compare comp 参数,允许您更改其默认行为。要使用它,您需要定义一个函子(一个覆盖 operator() 的类),它知道您希望如何比较指针。在这种情况下,您需要定义一个比较指向对象所具有的common_data_1

class Comparator 
  public:
    bool operator(A* left, A* right) 
        //You can do whatever logic you need here, here's an example:
        return (a->common_data_1) < (b->common_data_2);
    

然后,拨打您名单上的sort

ptrList.sort(Comparator());

【讨论】:

【参考方案2】:

我喜欢@IanPudney 的回答,虽然我通常使用 lambda:

ptrList.sort([](A* first, A* second)
               return first->common_data_1 < second->common_data_1;
            );

common_data_1 替换为您要用于排序的任何数据成员或函数。

【讨论】:

以上是关于指向派生对象的基类指针的 C++ 排序容器的主要内容,如果未能解决你的问题,请参考以下文章

为啥我可以通过指向派生对象的基类指针访问派生私有成员函数?

使用具有指向派生类对象的指针的基类指针数组调用派生类方法

重载赋值运算符 - 多态容器

从基类函数派生的类容器

如何在没有直接继承的情况下访问基类容器中的派生对象

C++ 容器与继承