C++双向链表DLinkedList的add、remove为何设为protected?protected适用场景
双向链表protected权限问题解答
相关代码
DNode类定义
typedef string Elem; // list element type class DNode { // doubly linked list node private: Elem elem; // node element value DNode* prev; // previous node in list DNode* next; // next node in list friend class DLinkedList; // allow DLinkedList access };
DLinkedList类定义
class DLinkedList { // doubly linked list public: DLinkedList(); // constructor ~DLinkedList(); // destructor bool empty() const; // is list empty? const Elem& front() const; // get front element const Elem& back() const; // get back element void addFront(const Elem& e); // add to front of list void addBack(const Elem& e); // add to back of list void removeFront(); // remove from front void removeBack(); // remove from back private: // local type definitions DNode* header; // list sentinels DNode* trailer; protected: // local utilities void add(DNode* v, const Elem& e); // insert new node before v void remove(DNode* v); // remove node v };
问题1:为什么将add()和remove()成员函数设置为protected?
- 这两个是链表的内部工具函数,本身就不适合对外暴露:函数入参需要传入
DNode*类型的指针,而DNode是链表的内部节点类,它的所有成员都是私有属性,只有DLinkedList被设为友元,外部使用者根本拿不到合法的DNode实例指针,就算把这两个函数设为public,用户也无法正常调用,暴露出来反而会干扰用户对公共接口的使用。 - 兼顾类的扩展性:如果后续需要基于
DLinkedList派生新的链表类型,比如有序双向链表、支持指定位置插入的双向链表等,派生类需要直接调用底层的节点插入、删除逻辑来实现自定义功能。如果把这两个函数设为private,派生类就无法访问,只能重复实现相同的节点操作逻辑,浪费开发成本。 - 符合面向对象的封装原则:既对外部调用者隐藏了底层实现细节,又给派生类开放了必要的扩展能力。
问题2:C++开发中应该在什么场景下使用protected关键字?
- 场景1:类的内部成员/方法不需要对外暴露,但明确该类会作为基类被继承,派生类需要访问这些内部成员时,优先使用protected。本题的双向链表就是典型的这类场景,平衡了封装性和扩展性。
- 场景2:模板方法设计模式中,基类定义的公共流程里的可重写步骤,通常声明为protected虚函数。外部调用者只能访问基类提供的public入口方法,子类可以通过重写protected的步骤函数来自定义流程逻辑,不会破坏对外的接口一致性。
- 场景3:基类中所有派生类都需要复用的公共属性,不需要外部直接修改/访问时,可以声明为protected。比如所有图形基类中的填充颜色、边框宽度属性,子类(矩形、圆形等)需要修改这些属性实现自身的绘制逻辑,但不需要暴露给外部调用者。
注意不要滥用protected:如果一个类没有被继承的需求,优先用private封装所有内部成员。protected相当于对所有派生类开放了内部实现,会提高基类和派生类的耦合度,不符合最小暴露的封装原则。
内容的提问来源于stack exchange,提问作者Earthman
相关产品推荐
相关产品推荐

