如何在C++中使用继承删除构造函数和运算符?

huangapple go评论67阅读模式
英文:

How to delete constructors and operators using inheritance in c++?

问题

假设我有两个类,no_copyno_move,它们是基类。从这些基类派生的任何类都可以修改它们的构造函数和运算符重载。

顾名思义,no_copy将只执行以下操作(注释掉了应该执行的内容):

class base : no_copy
{
    /*
       base(const base&)=delete;
       base& operator=(const base&)=delete;
    */
};

对于no_move也是一样的:

class base : no_move
{
    /*
       base(base&&)=delete;
       base& operator=(base&&)=delete;
    */
};

这些类(no_copyno_move)使得从它们派生的类不可复制移动

现在,我只是使用宏来实现这一点;

// 对于没有限定名称的类
#define __NO_COPY__(__class__) __class__::__class__(const __class__&)=delete; __class__& __class__::operator=(const __class__&)=delete;

// 对于带限定名称的类
#define __NO_COPY_LIB__(__qualified_name__,__class__) __qualified_name__::__class__(const __class__&)=delete; __class__& __qualified_name__::operator=(const __class__&)=delete;

不移动也是同样的技术。


编辑:
宏的示例;

假设有一个如下的类;

namespace wrapper
{
   class my_class {}

   __NO_COPY__(my_class)
}
__NO_COPY_LIB__(::wrapper::my_class,my_class)

这些宏运行良好,但不够优雅。而且它们不容易重构,因为这些宏可以出现在类的定义实现的任何地方。

像以下的语法将意味着所有这些内容都在类的定义中,并且可以非常容易地更改或修改;

class base : public attributes<no_copy,no_move> {};

attributes结构只是定义为;

template <typename... _BCs/*Base Classes*/>
struct attibutes : public _BCs... {};

现在显然继承的语法并不那么重要。我只想能够定义类是否可以复制、移动或不可以。如果还有除了继承之外的其他方法可以工作,请提出建议。

因此,我正在寻找的是易于重构的方法。


我尝试在线查找关于如何重载构造函数的解决方案。但到目前为止,我还没有找到有关如何使用继承删除构造函数或运算符重载的任何信息,因此我怀疑是否可能使用继承删除它们。

任何帮助将不胜感激。

英文:

Suppose I have two classes, no_copy and no_move which are base classes. From which any class can derive from and hence have their constructors and operators modified.

As the name suggests, no_copy will literally just do the following; (commented out what it should do)

class base : no_copy
{
    /*
       base(const base&)=delete;
       base& operator=(const base&)=delete;
    */
};

And the same for no_move,

class base : no_move
{
    /*
       base(base&&)=delete;
       base& operator=(base&&)=delete;
    */
};

These classes (no_copy & no_move) make it so that the class that derives from it should not be copyable or moveable.

Right now I am just using a macro to do this;

// For classes without a qualified name
#define __NO_COPY__(__class__) __class__::__class__(const __class__&)=delete; __class__& __class__::operator=(const __class__&)=delete;

// For classes with qualified names
#define __NO_COPY_LIB__(__qualified_name__,__class__) __qualified_name__::__class__(const __class__&)=delete; __class__& __qualified_name__::operator=(const __class__&)=delete;

And the same technique for not moving.


EDIT:
Examples of the macros;

suppose a class as such;

namespace wrapper
{
   class my_class {};

   __NO_COPY__(my_class);
}
__NO_COPY_LIB__(::wrapper::my_class,my_class);

The macros work just fine, but it doesn't look pretty. Moreover they are not easy to refactor as these macros can be anywhere in the definition or implementation.

A syntax like the following would mean that all of this in right there in the definition of the class and can be changed or modified very easily;

class base : public attributes<no_copy,no_move> {};

The attributes struct is just defined as;

template <typename... _BCs/*Base Classes*/>
struct attibutes : public _BCs... {};

Now obviously the syntax of inheriting doesn't matter that much. All I want it to be able to define where the class can be copied,moved or not. Also, if there is a method other than inheritance which could work please do suggest it.

As all I am looking for is the method that is easily refactorable.


I have tried finding solutions online about how to overload constructors. But so far I have not found anything about deleting them and hence I am doubting if it is even possible to delete constructors or operators using inheritance.

Any help would be greatly appreciated.

答案1

得分: 4

特殊成员函数将委托给其子对象(基类和成员)的相应函数,并且如果委托找到已删除或不可访问的函数,则将默认为已删除。

虽然您可以使用非静态成员来实现这一点,但使用基类更好,因为它启用了"空基类优化",不会造成额外开销。

struct no_copy
{
protected:
    no_copy() = default;
    no_copy(const no_copy&) = delete;
    no_copy& operator=(const no_copy&) = delete;
};

class important_class : no_copy {};

C++11之前的版本:

class no_copy // 成员默认为"private"
{
    no_copy(const no_copy&); // 不需要定义
    no_copy& operator=(const no_copy&); // 不需要定义
protected:
    no_copy() {}
}

这不会阻止派生类定义一个用户提供的特殊成员函数,明确避免调用基类版本,但如果这样做,就表示有意使派生类实际上是可复制的/可赋值的(或其他操作)。

英文:

Special member functions delegate to the corresponding functions of their subobjects (bases and members) and will be defaulted as deleted if that delegation finds a deleted or inaccessible function.

Although you could use a non-static member for this, using a base class is better because it enables the "Empty Base Optimization", not costing anything.

struct no_copy
{
protected:
    no_copy() = default;
    no_copy(const no_copy&) = delete;
    no_copy& operator=(const no_copy&) = delete;
};

class important_class : no_copy {};

pre-C++11 version:

class no_copy // members default to "private"
{
    no_copy(const no_copy&); // no definition needed
    no_copy& operator=(const no_copy&); // no definition needed
protected:
    no_copy() {}
};

This won't stop the derived class from defining a user-provided special member that explicitly avoids calling the base class version, but if you do that it shows intent to make the derived class actually be copyable/whatever after all.

答案2

得分: 1

根据C++20及其新的requires表达式,以前相当繁琐的任务(例如在C++20之前实现std::optional、混合等)现在变得非常简洁,因为我们可以根据特性有条件地删除特殊成员函数,以适用于通用可重用的attributes基类。

enum class options {
    no_default,
    no_copy,
    no_move,
};

template <options... opts>
struct attributes {
 protected:
    attributes() requires contains_v<options::no_default, opts...>               = delete;
    attributes() requires (!contains_v<options::no_default, opts...>)             = default;
    attributes(attributes const&) requires contains_v<options::no_copy, opts...> = delete;
    attributes& operator=(attributes const&) requires contains_v<options::no_copy, opts...> =
        delete;
    attributes(attributes&&) requires contains_v<options::no_move, opts...>            = delete;
    attributes& operator=(attributes&&) requires contains_v<options::no_move, opts...> = delete;
};

// 示例用法
struct A : attributes<options::no_move, options::no_copy> {
    A() = default;
};

// 辅助特性:
template <options opt, options head, options... tail>
struct contains {
    static constexpr bool value{opt == head || contains<opt, tail...>::value};
};

template <options opt, options head>
struct contains<opt, head> {
    static constexpr bool value{false};
};

template <options opt, options... opts>
constexpr bool contains_v{contains<opt, opts...>::value};

请注意,这是您提供的C++代码的翻译。如果您有任何其他问题或需要进一步的帮助,请随时提出。

英文:

As of C++20 and its new requires-expressions, this previously quite hasslesome of a task (e.g. implementing std::optional pre-C++20, mixins and so on) has now become quite neat, as we can conditionally delete a special member function based on traits to the common reusable attributes base class.

enum class options {
    no_default,
    no_copy,
    no_move,
};

template &lt;options... opts&gt;
struct attributes {
 protected:
    attributes() requires contains_v&lt;options::no_default, opts...&gt;               = delete;
    attributes() requires(!contains_v&lt;options::no_default, opts...&gt;)             = default;
    attributes(attributes const&amp;) requires contains_v&lt;options::no_copy, opts...&gt; = delete;
    attributes&amp; operator=(attributes const&amp;) requires contains_v&lt;options::no_copy, opts...&gt; =
        delete;
    attributes(attributes&amp;&amp;) requires contains_v&lt;options::no_move, opts...&gt;            = delete;
    attributes&amp; operator=(attributes&amp;&amp;) requires contains_v&lt;options::no_move, opts...&gt; = delete;
};

// Example usage
struct A : attributes&lt;options::no_move, options::no_copy&gt; {
    A() = default;
};

Helper trait:

template &lt;options opt, options head, options... tail&gt;
struct contains {
    static constexpr bool value{opt == head || contains&lt;opt, tail...&gt;::value};
};

template &lt;options opt, options head&gt;
struct contains&lt;opt, head&gt; {
    static constexpr bool value{false};
};

template &lt;options opt, options... opts&gt;
constexpr bool contains_v{contains&lt;opt, opts...&gt;::value};

huangapple
  • 本文由 发表于 2023年6月1日 21:37:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76382489.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定