Enc*_*ble 6 c++ constructor destructor
请原谅我,如果已经提出这个问题,我没有找到任何特定问题的答案.
我在库中创建了一个类,我希望某些类能够创建和销毁,其他类可以访问其他公共函数.有一个friend class不是我想要的,因为朋友类将访问我不想要的成员变量和成员函数.我偶然发现了这个几乎可以工作的习语,除了析构函数,因为它不能采用其他参数.有了这个成语,我得到:
class B;
class A
{
public:
class LifecycleKey
{
private:
LifecycleKey() {}
friend class B;
};
A(LifecycleKey); // Now only class B can call this
// Other public functions
private:
~A(); // But how can I get class B to have access to this?
void somePrivateFunction();
// Members and other private functions
};
Run Code Online (Sandbox Code Playgroud)
如上面的代码中所提到的,该解决方案不允许仅class B访问析构函数.
虽然上述问题都没有任何影响,因为我总是可以将ctor和dtor公之于众,并且只是说"RTFM".
我的问题是:
有没有办法限制访问ctor和dtor到特定的类(但只有ctor和dtor),同时坚持更熟知的语法(如果人们想要的东西在堆栈上,通过删除销毁,等等)?
任何帮助是极大的赞赏!
解
在 A.h
class B;
class A
{
protected:
A() {}
virtual ~A() {}
A(const A&); // Implement if needed
A(A&&); // Implement if needed
public:
// Public functions
private:
void somePrivateFunction();
// Members and other private functions
};
Run Code Online (Sandbox Code Playgroud)
在 B.h
class B
{
public:
B();
~B();
const A* getA() const;
private:
A* m_a;
}
Run Code Online (Sandbox Code Playgroud)
在 B.cpp
namespace {
class DeletableA : public A {
public:
DeletableA() : A() {}
DeletableA(const DeletableA&); // Implement if needed
DeletableA(DeletableA&&); // Implement if needed
~DeletableA() {}
}
}
#include B.h
B::B() : m_a(new DeletableA()) {}
B::~B() { delete static_cast<DeletableA*>(m_a); }
const A* B::getA() const { return m_a; }
Run Code Online (Sandbox Code Playgroud)
或者,如果DeletableA需要类B.h或A.h(由于内联,模板或希望将所有class A相关的类放入其中A.h),可以使用构造函数上的"传递键"将其移动到那里,以便其他类不能创建一个.即使析构函数将被暴露,也没有其他类可以DeletableA删除.
显然,这个解决方案需要class B知道如何制作实例Deletable A(或者如果它没有暴露在一般地创建类A.h),并且只存储A*通过公共函数公开的存储,但是,它是建议的最灵活的设置.
虽然某些其他类仍然可以创建class A(因为class A不是"final")的子类,但是如果您愿意,可以向A的构造函数添加另一个"密钥"以防止此类行为.
为了实现这一目标,该类B应该是唯一能够实例化和销毁该类对象的类A:
对于静态和自动变量,只需要限制对构造函数的访问,并且您已经这样做了。
对于动态分配的对象,您可以限制对其释放函数 、operator delete和 的访问operator delete[],并将析构函数保留为公共。这会禁止除删除对象之外的其他代码B。
对于动态对象,您可以从具有虚拟析构函数或命名自毁函数的A接口派生类,该函数将类作为友元。然后可以通过强制转换到它有权访问的接口来销毁任何动态对象。protectedBBA
显式调用析构函数的代码值得得到任何好处。
请记住,您永远不会构建针对恶意代码的坚不可摧的防御,您只是构建合理的检测和编译时报告无意的错误使用。