【问题标题】:Program design with polymorphism and differing data structures具有多态性和不同数据结构的程序设计
【发布时间】:2026-02-07 22:00:01
【问题描述】:

我认为我在这里遇到了设计问题,非常感谢您的帮助。

我有一个表示基本算法的 Base 类。

class BaseAlgo: public Algo<double>
{
public:

/// data structures
// ...
// 
 struct Item {
    double profit;
    double weight;
    double xjSolution;
 };

 typedef std::pair<double, std::vector<Item>::iterator> ScaledItem;

protected:

 std::vector<Item> & items_;
 boost::ptr_vector<ScaledItem> largeItems_;
}

BaseAlgo 有一些功能,其中一些是虚拟的,另一些则不是。

作为派生类我有

class DerivedAlgo: public BaseAlgo
{
public:

/// enhanced data structures
// ...
// 

 struct DerivedScaledItem : ScaledItem {
    int additional;
 };
 }

在我在 DerivedAlgo 中重载的虚函数中,我需要访问 DerivedScaledItem 的附加参数,这并不是多态性的初衷。是否有可能,或者您是否提出了不同的设计方法?我现在对任何事情都持开放态度,因为我完全被困住了。

现在,BaseAlgo 中的 largeItems_ 成员 ptr_vector 持有 ScaledItems(内部作为指针)。我想,我可以像这样使用它:

// in DerivedAlgo

void someMethod(std::vector<Item>::iterator someiterator){
   DerivedScaledItem doubledItem = {};

   doubledItem.first = 4.5;
   doubledItem.second = someiterator;
   doubledItem.additional= 2;
   largeItems_.push_back(new UnboundedScaledItem(doubledItem));
   boost::ptr_vector<DerivedScaledItem>::iterator it = largeItems_.begin();
   std::cout << "added large item " << *it << std::endl;
}

当我计算刚刚添加的对象时,addition 设置为 2。但之后,调用 largeItems_ 的 getter,附加字段将设置回 0,然后只设置 ScaledItem 中已知的两个字段。

// in BaseAlgo
const boost::ptr_vector<ScaledItem>& getLargeItems() const
{
    return largeItems_;
}

// from my test.cpp
DerivedAlgo obj;
// ... define someiterator
obj.someMethod(someiterator);
boost::ptr_vector<BaseAlgo::ScaledItem> largeItems = knapsack.getLargeItems();
boost::ptr_vector<DerivedAlgo::DerivedScaledItem>::iterator it = largeItems.begin();
std::cout << "read large item " << *it << std::endl;

【问题讨论】:

    标签: c++ boost vector polymorphism pointers


    【解决方案1】:

    我猜你没有告诉 boost 如何克隆你的 ptr_vector-s 元素,如下所述: http://www.boost.org/doc/libs/1_54_0/libs/ptr_container/doc/tutorial.html#cloneability

    因此,在这一行中,您创建了向量的副本(您可以通过将 largeItems 声明为引用来避免这种情况),它们通过 ScaledItem 的构造函数进行复制,这会丢失您的额外成员。

    boost::ptr_vector<BaseAlgo::ScaledItem> largeItems = knapsack.getLargeItems();
    

    关于您对另一个设计的问题:

    • 您可以将向量元素的类型作为模板参数传递给基类。
    • 您可以将向量移动到派生类中,并仅提供(虚拟、抽象)函数来访问基类中的单个元素。如果基类也应该能够创建元素,您可能需要某种工厂方法。因为您不想要向量中的基本元素类型。

    【讨论】:

    • 首先:感谢您的回答!我喜欢模板参数的想法,今晚我会试试这个。另外,我会尝试在我的测试代码中声明 largeItems 作为参考是否可以解决问题,但这似乎是有道理的!
    • 好的,将 largeItems 声明为 const 引用解决了这个问题。但我有一个后续问题:当我将 BaseAlgo::ScaledItems 的迭代器作为虚函数的函数参数时会发生什么?当我声明基类型的迭代器时,附加参数是否会自动丢失?
    • :) 已经解决了,我使用动态转换并将 ScaledItem 从 typedef 更改为带有虚拟析构函数的真实结构以使其工作。