C++ 使用子类操作类

C++ 使用子类操作类,c++,inheritance,linked-list,C++,Inheritance,Linked List,在这个模板问题中,有一个名为list的用户创建的链表类,它没有删除最后一个元素的方法,我们假设不能直接更改它 template<typename T> class List { public: class Iterator { public: T get_data() { T to_be_returned = current->data; return to_be_returned;

在这个模板问题中,有一个名为list的用户创建的链表类,它没有删除最后一个元素的方法,我们假设不能直接更改它

template<typename T>
class List {
public:
    class Iterator {
    public:
        T get_data() { 
            T to_be_returned = current->data;
            return to_be_returned;
        }
        void next_element() {
            current = current->next;
        }
        bool has_more_elements() {
            return current != NULL;
        }
    private:
       //...
    };
public:
    List();
    ~List();
    void print();
    void push_front(T x);
    void push_back(T x);
    Iterator get_iterator(); 
private:
   //...
};

问题的下一部分是假设我们只需要在最后一个元素是第一个小写字符的单词时删除它,是否可以用模板实现这一点?如果不是,我们如何解决它?

您的代码中有几个问题

首先,若要从中继承列表,它需要

虚拟公共析构函数,或, 非虚拟受保护的析构函数。 否则,任何使用指向列表的指针/引用来引用MyList对象的用户代码在调用相应对象的析构函数时都会出现内存泄漏

如果不允许您触摸提供的列表代码,您可以通过受保护或私有机制从中继承,以确保指向列表的指针不会造成任何问题。但是,您需要记住,当您使用List*或List&时,您将无法使用List提供的公共API

那么,你还有另一个问题。在您的问题中,您提到您必须在最后一次执行remove_。但是,您在MyList::remove\u lastList&l中的签名与要求不匹配。我认为,你应该更改签名以满足这一要求

我在代码摘录中看到的另一个问题是,您显式调用了析构函数MyList::~MyList。只要在相应的行上满足else条件,应用程序中就会有未定义的行为。想想这个案子

/*一些代码*/ { 糜棱岩糜棱岩; /*填写清单,用它做点什么*/ mylist.remove_last;/*假设您已更改签名*/ /*假设您已经点击了上面提到的else语句*/ /*离开作用域时,mylist将被销毁*/ /*双重破坏问题*/ } /*一些代码*/ 请参阅中提供的注释

请注意,直接为普通对象(如局部变量)调用析构函数会在作用域末尾再次调用析构函数时调用未定义的行为

最后,为了回答你的问题,你应该考虑写一些大致的东西:

/*私有继承以避免可能的泄漏*/ /*这意味着列表是您的实现细节*/ /*然后,您需要正确地显示列表的API*/ 模板类MyList:私有列表{ 公众: 最后删除{ autoit=List::get\u迭代器; /*通过遍历列表到达最后一个元素*/ 虽然它有更多的元素 it.next_元素; /*对迭代器执行一些操作,因为您知道它有最后一个元素 *现在*/ } }; 在这种情况下,您提供的代码不足以给出具体的答案,因为显然,列表的迭代器API只提供了push_back和push_front功能。您的列表或其迭代器上需要一些公共功能才能修改底层数据。此外,请记住,在我的解决方案建议中,它不是实际的数据点;它是用于过去结束迭代器的哨兵

如果您确定没有其他可用的公共功能,则可以创建一个列表并在向后推送值的同时遍历变量,直到到达最后一个元素,如中所示:

模板类MyList:私有列表{ 公众: 最后删除{ 列表温度; 自动当前=列表::获取迭代器; 自动前置{current}; 而current.has_有更多的元素{ prev=当前值; 当前.next_元素; 如果当前。有多个元素 temp.push_Back Prev.get_数据; } List::operator=std::movetemp;/*调用复制/移动分配*/ } }; 最后评论:

由于您没有提供, 请不要使用NULL,因为在本例中,它很可能指的是NULL ptr,这是最好使用的。 编辑。在这个问题上,我认为模板可以派上用场的唯一地方是用户应用一些谓词函数。考虑以下修改,例如:

模板类MyList:私有列表{ 公众: 模板无效删除\u lastPredicate&&pred{ 列表温度; 自动当前=列表::获取迭代器; 自动前置{current}; 而current.has_有更多的元素{ prev=当前值; 当前.next_元素; 如果当前。有多个元素{ 自动值=上一次获取数据; 如果是pred值 温度push_backsd::movevalue; } } List::operator=std::movetemp;/*调用复制/移动分配*/ } 最后删除{ 删除_last[]const T&{return true;}; } void remove_last_如果单词小写{ 移除最后一个[]常数&{ /*仅当单词和以小写逻辑开头时才应用**/ //返回。。。; }; } };
如上所述,您可以避免谓词的代码重复,并允许使用模板谓词函子进行编译器端优化。

remove\u last函数不应该从自身中删除最后一个元素吗?不重建传入的列表…@super因为我无法更改列表中的私有成员,所以我要做的是创建一个MyList对象并将列表中除最后一个元素以外的所有元素推回MyList…非常感谢您的回复。但是从私有继承不会破坏封装吗?从private继承是否允许我直接访问列表的私有成员?您还说您将无法使用List提供的公共API,但迭代器是公共的。。继承后我能使用它吗?您的解决方案中的最后一个问题while current.have_more_元素如何在不将List对象传递给MyList的情况下访问子类中父类的元素?我不知道您所说的破坏封装是什么意思,但您应该看看参考,以了解公共继承、受保护继承和私有继承之间的区别。不,私有继承不允许这样的访问。类的私有成员总是私有的,除了类的成员和/或朋友之外,不能访问任何对象。请阅读参考资料。。。这里解释了所有关于成员访问父类的问题。我如何访问子类中父类的元素而不将List对象传递给MyList。好吧,子类也是它的父类,这就是为什么要使用继承。你可以把继承看作是由其他类组成的,当然它们是不同的东西;但是对于这个例子,你可以这样想。子类可以通过调用Parent1::something来引用它从Parent1继承的部分/功能。您应该阅读一些关于派生类的资料。请查看我答案的最终版本,在编辑部分,我提供了一个模板化的remove_last member函数。
template<typename T>
class MyList : public List<T>
{
public:
    void remove_last(List<T>& l)
    {
        typename MyList<T>::Iterator it = l.get_iterator();
        typename MyList<T>::Iterator it2 = it;

        if(!it.has_more_elements())
            return;

        this->push_back(it.get_data());
        it2.next_element();
        it.next_element();
        if(it.has_more_elements())
            it.next_element();
        else
            return MyList<T>::~MyList();

        while(it.has_more_elements())
        {
            this->push_back(it2.get_data());
            it2.next_element();
            it.next_element();
        }
    }
};