C++ 如何在父类型中限制子类型?
我有一个这样的类类型:C++ 如何在父类型中限制子类型?,c++,C++,我有一个这样的类类型: struct permanent_runnable { static std::vector<permanent_runnable*> instants; protected: permanent_runnable() { instants.push_back(this); } public: virtual ~permanent_runnable() {} virtual void start() =
struct permanent_runnable {
static std::vector<permanent_runnable*> instants;
protected:
permanent_runnable() {
instants.push_back(this);
}
public:
virtual ~permanent_runnable() {}
virtual void start() = 0;
virtual void stop() = 0;
};
#include <vector>
template<class Type>
struct container
{
static std::vector<Type*> instants;
};
struct controller {
virtual void start() = 0;
virtual void stop() = 0;
virtual ~controller() {}
};
template<class Type>
std::vector<Type*> container<Type>::instants;
template<class Type>
struct permanent_runnable :public controller {
protected:
permanent_runnable() { container<controller>::instants.push_back(this); }
permanent_runnable(const permanent_runnable&) = delete;
permanent_runnable& operator=(const permanent_runnable&) = delete;
public:
virtual ~permanent_runnable() {}
static Type& instance() {
return ins;
}
private:
static Type ins;
};
template<class Type>
Type permanent_runnable<Type>::ins;
struct A :public permanent_runnable<A> {
virtual void start() {
std::cout << "A::start" << std::endl;
}
virtual void stop() {
std::cout << "A::stop" << std::endl;
}
~A(){
std::cout << "!~A" << std::endl;
}
};
struct B :public permanent_runnable<B> {
virtual void start() {
std::cout << "B::start" << std::endl;
}
virtual void stop() {
std::cout << "B::stop" << std::endl;
}
~B() {
std::cout << "!~B" << std::endl;
}
};
int main() {
A::instance();
A::instance();//for check
B::instance();
B::instance();//for check
for (auto ins : container<controller>::instants) {
ins->start();
ins->stop();
ins->~controller();
}
auto size = container<controller>::instants.size();
container<controller>::instants.clear();
size = container<controller>::instants.size();
return 0;
}
我希望从这个永久的可运行类型继承的所有类型都没有复制构造函数和可分配的运算符。如果有人不遵守规则,将输出编译错误
我能做些什么来存档呢?你不能阻止用户做一些不想要的事情。如果他们足够努力,就会找到办法。话虽如此,使基类不可赋值和不可复制构造是一个很好的指示,表明派生类也不应提供:
struct base {
base() = default;
base& operator=(const base&) = delete;
base(const base&) = delete;
};
struct derived : base {};
int main()
{
derived a;
//derived b(a); // error
derived c;
//c = a; // error
}
我想您实际上希望永久运行是不可分配和不可复制构造的,因为在类本身可以复制构造和分配时要求派生类的永久运行是不合理的。您无法阻止用户做不希望的事情。如果他们足够努力,就会找到办法。话虽如此,使基类不可赋值和不可复制构造是一个很好的指示,表明派生类也不应提供:
struct base {
base() = default;
base& operator=(const base&) = delete;
base(const base&) = delete;
};
struct derived : base {};
int main()
{
derived a;
//derived b(a); // error
derived c;
//c = a; // error
}
我想您实际上希望永久运行是不可分配和不可复制构造的,因为要求派生类的永久运行而类本身可以复制构造和分配是不合理的。最后,我实现了如下:
struct permanent_runnable {
static std::vector<permanent_runnable*> instants;
protected:
permanent_runnable() {
instants.push_back(this);
}
public:
virtual ~permanent_runnable() {}
virtual void start() = 0;
virtual void stop() = 0;
};
#include <vector>
template<class Type>
struct container
{
static std::vector<Type*> instants;
};
struct controller {
virtual void start() = 0;
virtual void stop() = 0;
virtual ~controller() {}
};
template<class Type>
std::vector<Type*> container<Type>::instants;
template<class Type>
struct permanent_runnable :public controller {
protected:
permanent_runnable() { container<controller>::instants.push_back(this); }
permanent_runnable(const permanent_runnable&) = delete;
permanent_runnable& operator=(const permanent_runnable&) = delete;
public:
virtual ~permanent_runnable() {}
static Type& instance() {
return ins;
}
private:
static Type ins;
};
template<class Type>
Type permanent_runnable<Type>::ins;
struct A :public permanent_runnable<A> {
virtual void start() {
std::cout << "A::start" << std::endl;
}
virtual void stop() {
std::cout << "A::stop" << std::endl;
}
~A(){
std::cout << "!~A" << std::endl;
}
};
struct B :public permanent_runnable<B> {
virtual void start() {
std::cout << "B::start" << std::endl;
}
virtual void stop() {
std::cout << "B::stop" << std::endl;
}
~B() {
std::cout << "!~B" << std::endl;
}
};
int main() {
A::instance();
A::instance();//for check
B::instance();
B::instance();//for check
for (auto ins : container<controller>::instants) {
ins->start();
ins->stop();
ins->~controller();
}
auto size = container<controller>::instants.size();
container<controller>::instants.clear();
size = container<controller>::instants.size();
return 0;
}
最后,我实现了如下:
struct permanent_runnable {
static std::vector<permanent_runnable*> instants;
protected:
permanent_runnable() {
instants.push_back(this);
}
public:
virtual ~permanent_runnable() {}
virtual void start() = 0;
virtual void stop() = 0;
};
#include <vector>
template<class Type>
struct container
{
static std::vector<Type*> instants;
};
struct controller {
virtual void start() = 0;
virtual void stop() = 0;
virtual ~controller() {}
};
template<class Type>
std::vector<Type*> container<Type>::instants;
template<class Type>
struct permanent_runnable :public controller {
protected:
permanent_runnable() { container<controller>::instants.push_back(this); }
permanent_runnable(const permanent_runnable&) = delete;
permanent_runnable& operator=(const permanent_runnable&) = delete;
public:
virtual ~permanent_runnable() {}
static Type& instance() {
return ins;
}
private:
static Type ins;
};
template<class Type>
Type permanent_runnable<Type>::ins;
struct A :public permanent_runnable<A> {
virtual void start() {
std::cout << "A::start" << std::endl;
}
virtual void stop() {
std::cout << "A::stop" << std::endl;
}
~A(){
std::cout << "!~A" << std::endl;
}
};
struct B :public permanent_runnable<B> {
virtual void start() {
std::cout << "B::start" << std::endl;
}
virtual void stop() {
std::cout << "B::stop" << std::endl;
}
~B() {
std::cout << "!~B" << std::endl;
}
};
int main() {
A::instance();
A::instance();//for check
B::instance();
B::instance();//for check
for (auto ins : container<controller>::instants) {
ins->start();
ins->stop();
ins->~controller();
}
auto size = container<controller>::instants.size();
container<controller>::instants.clear();
size = container<controller>::instants.size();
return 0;
}
您可以合理地做的就是删除复制构造函数和复制赋值。派生类型可以有这些运算符,但不能复制基类的对象。他们需要创建一个全新的实例。这样就实现了您想要的,而且对于派生类型真的没有什么可担心的。基类将防止错误地复制,并给出关于其使用的明确意图
任何想要复制的人当然都可以复制——未定义的行为并不意味着如果你进入机器级别,你就不能做任何你想做的事情。我的意思是:如果我真的想复制这个对象,我会仔细阅读你所在架构的ABI规范,并使用低级原语复制。如果没有代码审查文化,您就无法真正防止这种情况,但无论如何,您不必担心这一点:您可以合理地做的就是删除复制构造函数和复制赋值。派生类型可以有这些运算符,但不能复制基类的对象。他们需要创建一个全新的实例。这样就实现了您想要的,而且对于派生类型真的没有什么可担心的。基类将防止错误地复制,并给出关于其使用的明确意图
任何想要复制的人当然都可以复制——未定义的行为并不意味着如果你进入机器级别,你就不能做任何你想做的事情。我的意思是:如果我真的想复制这个对象,我会仔细阅读你所在架构的ABI规范,并使用低级原语复制。如果没有适当的代码审查文化,您就无法真正防止这种情况发生,但这并不是您应该担心的问题:您的意思是?如果您允许子类化,您就不必指定关于什么的术语,如果它们创建任何构造函数。@tadman final只能用于虚拟函数。。。复制构造函数不能是虚拟的。@AdrianMole在类或结构上使用时,意味着您不能子类化。当在函数上使用时,这意味着@tadman将不会有OP的情况……所有类型都继承自此……如果您真的想锁定它,最好将该类设为最终类,并使用其他机制将该功能添加为用户扩展。关于如何做到这一点,你肯定可以从中获得灵感。你是说?如果您允许子类化,您就不必指定关于什么的术语,如果它们创建任何构造函数。@tadman final只能用于虚拟函数。。。复制构造函数不能是虚拟的。@AdrianMole在类或结构上使用时,意味着您不能子类化。当在函数上使用时,这意味着@tadman将不会有OP的情况……所有类型都继承自此……如果您真的想锁定它,最好将该类设为最终类,并使用其他机制将该功能添加为用户扩展。对于如何做到这一点,你肯定可以从中获得灵感。