C++的保护类型还能这么玩
将一个类的析构函数定义为 protected 保护类型:
这个类就不能在外部被析构,被定义。只能在它的子类,或者它的友元类里面去定义。
定义了 保护类型的 析构函数,它的声明周期在 子类或者 友元类里面自动管理。
最主要理解它的限制,理解生命周期就好。
定义为保护类型的好处:
将一个类的析构函数定义为 protected
类型在某些情况下是有用的,主要是为了控制类的继承和对象的生命周期。以下是几种情况下将析构函数定义为 protected
的用途:
-
基类设计限制:当你设计一个基类时,你可能希望阻止其他类直接实例化该基类,而只能通过继承该基类来创建对象。将析构函数定义为
protected
可以防止直接实例化该基类,只有派生类才能调用基类的析构函数,从而实现了对基类对象的间接控制。 -
限制继承:有时,你可能希望只允许特定的派生类实例化,而不是所有的派生类。将基类的析构函数定义为
protected
可以确保只有派生类可以调用析构函数,而其他类则不能。 -
对象生命周期管理:在某些情况下,你可能需要手动管理对象的生命周期,而不是依赖于自动的栈上或堆上的对象销毁。将析构函数定义为
protected
可以防止用户直接销毁对象,只能通过派生类的方法来释放资源,从而更灵活地管理对象的生命周期。 -
资源管理:如果类持有某些资源(如文件句柄、数据库连接等),你可能希望确保这些资源在对象销毁时得到正确释放。将析构函数定义为
protected
可以让你控制资源的释放过程,并确保资源在适当的时候被释放,避免资源泄漏。
总的来说,将析构函数定义为 protected
类型可以提供更加灵活的对象生命周期管理和资源管理机制,并控制对象的继承和销毁行为,从而增强了类的封装性和安全性。
#include <iostream> #include <cstdint> #include <string> #include <cstring> class BaseA { protected: BaseA() { std::cout << "BaseA 构造函数被调用" << std::endl; } ~BaseA() { std::cout << "BaseA 析构函数被调用" << std::endl; } friend class BaseB; // 将BaseB声明为友元类 public: void print() { std::cout << "这是BaseA类的print函数" << std::endl; } }; class BaseB { private: BaseA objA; // BaseA的对象作为成员变量 protected: BaseB() { std::cout << "------- BaseB 构造函数被调用" << std::endl; } ~BaseB() { std::cout << "------- BaseB 析构函数被调用" << std::endl; } public: void print() { std::cout << "------- 这是BaseB类的print函数" << std::endl; objA.print(); // 调用BaseA类的print函数 } }; class DriveC : public BaseB { public: DriveC() { std::cout << "<<<----->>> DriveC 构造函数被调用" << std::endl; } ~DriveC() { std::cout << "<<<----->>> DriveC 析构函数被调用" << std::endl; } void print() { std::cout << "<<<----->>> 这是DriveC类的print函数" << std::endl; BaseB::print(); // 调用BaseB类的print函数 } }; int main(){ DriveC c; // 创建DriveC对象 std::cout<<"-------------------------------------------\r\n"; c.print(); // 调用DriveC对象的print函数 return 0; }
输出结果:
BaseA 构造函数被调用 ------- BaseB 构造函数被调用 <<<----->>> DriveC 构造函数被调用 ------------------------------------------- <<<----->>> 这是DriveC类的print函数 ------- 这是BaseB类的print函数 这是BaseA类的print函数 <<<----->>> DriveC 析构函数被调用 ------- BaseB 析构函数被调用 BaseA 析构函数被调用