【问题标题】:Using assignment operator recursively递归使用赋值运算符
【发布时间】:2015-02-25 05:02:12
【问题描述】:

有人能告诉我为什么递归operator= 没有在这里编译吗?任务很简单。我有一个Menu<T> 类,其中T 是菜单中每个选项的类型。 Menu<WeightedItem<T>> 类只是 Menu<T> 的特化,其中 WeightedItem<T> 包含项目 T 以及 int 数据成员(用于概率目的)。

我想通过使用其项目并附加一些概率权重(其值与问题无关)将Menu<T> 转换为Menu<WeightedItem<T>>。问题是菜单可以有子菜单,而子菜单又可以有子菜单,因此我需要递归使用operator=。到目前为止,这是我的代码:

template <typename T> struct WeightedItem;

template <typename T>
struct Menu
{
    struct Option
    {
        const T item;
        Menu* submenu;
        Option* next;
        Option(const T& t, Menu<T>* menu = nullptr) 
            : item(t),
            submenu(menu),
            next(nullptr)
        {}
    };

    Option* first; // first option in the menu
};


template <typename T>
struct WeightedItem {
    T item;
    int probabilityWeight;
};

template <typename T>
struct Menu<WeightedItem<T>>
{
    struct Option
    {
        const WeightedItem<T> item;
        Menu* submenu;
        Option* next;
        Option(const WeightedItem<T>& t, Menu<WeightedItem<T>>* menu = nullptr)
            : item(t),
            submenu(menu),
            next(nullptr)
        {}
        Option& operator=(const Option& other)
        {
            // Needed for defining Menu& operator=(const Menu<T>&).
            if (this == & other)
                return *this;
            item = other.item;
            submenu = other.submenu;
            next = other.next;
            return *this;
        }
    };
    Option* first;
    Menu & operator=(const Menu<T>&);
};

template <typename T>
Menu<WeightedItem<T>>& Menu<WeightedItem<T>>::operator=(const Menu<T>& other)
{
    delete first;
    if (!other.first)
        first = nullptr;
    else
    {
        int weight = 1;
        Menu<WeightedItem<T>> submenu operator=(*other.first->submenu); // Recursive operator= call for submenus.  Won't compile.
        first = new Menu<WeightedItem<T>>::Option({other.first->item, weight}, &submenu);
        Option* current = first->next;
        for (typename Menu<T>::Option* o = other.first->next; o; o = o->next)
        {
            Menu<WeightedItem<T>> submenu operator=(*o->submenu); // Recursive operator= call for submenus.  Won't compile.
            current = new Menu<WeightedItem<T>>::Option({o->item, ++weight}, &submenu);
            current = current->next;
        }
    }
    return *this;
}

struct Item {};

int main() {
    Menu<Item> menu;
    Menu<WeightedItem<Item>> weightedMenu;
    weightedMenu = menu;
}

但是这两个递归调用似乎是非法的。为什么?

[Error] expected initializer before 'operator'

如果是非法的,如何解决?

更新: 好的,所有的深度复制都使用new 进行了多次分配。我不得不简单地放弃 operator= 的想法,而是简单地定义一个递归函数。我测试了结果也是准确的:

template <typename T> struct WeightedItem;

template <typename T>
struct Menu {
    struct Option {
        const T item;
        Menu* submenu;
        Option* next;
        Option (const T& t, Menu<T>* menu = nullptr): item(t), submenu(menu), next(nullptr) {}
    };
    Option* first = nullptr;
};


template <typename T>
struct WeightedItem {
    T item;
    int probabilityWeight;
};

template <typename T>
struct Menu<WeightedItem<T>> {
    struct Option {
        const WeightedItem<T> item;
        Menu* submenu;
        Option* next;
        Option (const WeightedItem<T>& t, Menu<WeightedItem<T>>* menu = nullptr): item(t), submenu(menu), next(nullptr) {}
    };
    Option* first = nullptr;
    inline void inheritFrom (const Menu<T>&);
};

template <typename T>
inline void Menu<WeightedItem<T>>::inheritFrom (const Menu<T>& other) {
    if (!other.first)
        first = nullptr;
    else {
        int weight = 1;
        Menu<WeightedItem<T>>* submenu = nullptr;
        if (other.first->submenu) {
            submenu = new Menu<WeightedItem<T>>;    
            submenu->inheritFrom (*other.first->submenu);  // Recursive call for submenus.
        }
        first = new Menu<WeightedItem<T>>::Option ({other.first->item, weight}, submenu);
        Option *current = first->next, *prev = first;
        for (typename Menu<T>::Option* o = other.first->next;  o;  o = o->next) {
            Menu<WeightedItem<T>>* submenu = nullptr;
            if (o->submenu) {
                submenu = new Menu<WeightedItem<T>>;
                submenu->inheritFrom (*o->submenu);  // Recursive call for submenus.
            }
            current = new Menu<WeightedItem<T>>::Option ({o->item, ++weight}, submenu);
            prev->next = current;
            if (o->next) {
                prev = current;
                current = current->next;
            }
        }
    }
}

struct Item {};

int main() {
    Menu<Item> menu;
    Menu<WeightedItem<Item>> weightedMenu;
    weightedMenu.inheritFrom(menu);
}

但是,关于递归使用 = 的原始问题仍未得到解答。而且看来c++不支持,因为当我尝试用=翻译上面的时候,它没有编译。

【问题讨论】:

  • 请贴出编译器给出的错误信息。
  • Menu&lt;WeightedItem&lt;T&gt;&gt; submenu = *o-&gt;submenu; 不调用任何operator =;这是初始化而不是赋值。
  • 使用Menu&lt;WeightedItem&lt;T&gt;&gt; submenu operator= (*other.first-&gt;submenu);?仍然无法编译。
  • 您不应在作业中使用“操作员”一词。

标签: c++ variable-assignment operator-keyword


【解决方案1】:

替换

   Menu<WeightedItem<T>> submenu operator=(*other.first->submenu);
   first = new Menu<WeightedItem<T>>::Option({other.first->item, weight}, &submenu);

通过

   first = new Menu<WeightedItem<T>>::Option({other.first->item, weight}, &submenu);
   first->submenu->operator=(*other.first->submenu);

或通过

   first = new Menu<WeightedItem<T>>::Option({other.first->item, weight}, &submenu);
   *first->submenu = *other.first->submenu;

这是解决问题的起点,但真正的解决方案需要每个选项中的选项和子菜单的深层副本。

【讨论】:

  • 但是 submenu 没有定义。你的意思是other.first-&gt;submenu 而不是&amp;submenu?那仍然无法编译。
  • @prestokeys,你需要添加逻辑来实现子菜单的深拷贝。查找代码/逻辑以制作单链表的深层副本以解决您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 2011-08-02
  • 2019-10-06
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 2013-11-30
相关资源
最近更新 更多