为什么有人会声明构造函数受保护?我知道构造函数被声明为私有是为了不允许在堆栈上创建它们。
9 回答
当一个类(旨在)是一个抽象类时,受保护的构造函数是完全正确的。在这种情况下,您不希望从类中实例化对象,而只使用它来继承。
还有其他用例,例如某些构造参数集应仅限于派生类。
当存在无法单独由构造函数保证的构造要求时,非公共构造函数很有用。例如,如果需要在构造函数之后立即调用初始化方法,或者如果对象需要向某个容器/管理器对象注册自身,则必须在构造函数之外完成。通过限制对构造函数的访问并仅提供工厂方法,您可以确保用户接收到的任何实例都将履行其所有保证。这也常用于实现 Singleton,这实际上只是该类做出的另一个保证(即只有一个实例)。
使构造函数受保护而不是私有的原因与使任何其他方法或字段受保护而不是私有的原因相同:以便它可以被子级继承。也许您希望基类中有一个公共的、非虚拟的工厂方法,它返回对派生类实例的引用;派生类显然想要访问父构造函数,但您仍然不想在工厂之外创建它们。
当类的方法都不是纯虚拟的时,受保护的构造函数可用于使类有效地抽象。
它在 C++ 意义上不是很抽象,因为友元类仍然可以使用它而无需覆盖,但是您必须声明它们。
一种用途可能是工厂模式
受保护的构造函数意味着只有派生成员才能使用该构造函数构造类(和派生实例)的实例。这听起来有点鸡和蛋,但在实现类工厂时有时很有用。
对于有副作用的工厂方法。
class mine {
private:
mine () {};
protected:
mine(int id) : m_id(id) {};
int m_id;
static int m_count;
public:
static mine* CreateOneOfMe() {
return mine(m_count++);
}
int GetId() { return m_id; }
};
这会创建类的实例并保证它们中的每一个都有一个唯一的递增整数 id。请注意,如果您要使用的构造函数不是默认的,您也必须隐藏默认值。
让子类使用实例化器不能直接访问的构造函数。
您可以使用它来限制可以创建它的类,例如:
class Level
{
private:
Level();
~Level();
friend class LevelManager;
};
唯一可以创建其实例的类是 LevelManager 类,因此您将始终知道 Level 实例是在 LevelManager 中创建的。
受保护构造函数的一种用途是实现 CRTP 模式,请参见下面的代码:
#include <iostream>
#include <assert.h>
template <class T>
class ComparableMixin {
public:
bool operator !=(ComparableMixin &other) {
return ~(*static_cast<T*>(this) == static_cast<T&>(other));
}
bool operator <(ComparableMixin &other) {
return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
}
bool operator >(ComparableMixin &other) {
return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
}
bool operator >=(ComparableMixin &other) {
return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
}
protected:
ComparableMixin() {}
};
class Integer: public ComparableMixin<Integer> {
public:
Integer(int i) {
this->i = i;
}
int i;
bool operator <=(Integer &other) {
return (this->i <= other.i);
}
bool operator ==(Integer &other) {
return (this->i == other.i);
}
};
int main() {
Integer i(0) ;
Integer j(1) ;
//ComparableMixin<Integer> c; //compilation error!
assert (i < j );
assert (i != j);
assert (j > i);
assert (j >= i);
return 0;
}