“亲友” CRTP继承中的基类是否也影响子类? [英] Does "friending" the base class in CRTP inheritance affect the child class as well?

查看:178
本文介绍了“亲友” CRTP继承中的基类是否也影响子类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试回答另一个问题时,我想出了一个计划,强制CRTP基类的孩子接受一个特定类型作为它们的构造函数中的一个参数:使参数类型的构造函数 private ,将CRTP基类分配为朋友,并将参数类型声明为基类构造函数的参数。



但是,当我试图证明这个方案通过访问违规提供了所需的保护时,我发现即使参数类型的构造函数是私有的,以构建它:

  template< typename T> 
class SingletonBase {
protected:class P {friend class SingletonBase< T> P()= default; };
public:
SingletonBase(P){}
};

class Logger:public SingletonBase< Logger> {
using BASE = SingletonBase< Logger> ;;
public:
Logger():BASE {P {}} {} //为什么没有访问权限?
};

无错误编译,即使我希望存取违规。为什么?

解决方案


在CRTP继承中基类是否会影响子类? / p>

不,当然不是。友谊不是继承的。为了说明这个问题,



首先, P :: P()是一个默认的默认构造函数, a href =http://en.cppreference.com/w/cpp/language/default_constructor#Trivial_default_constructor =nofollow>琐碎的默认构造函数。



其次, P {} value initialization (since C ++ 11),



(强调我)


2)如果 T 是一个类类型,默认构造函数既不是用户提供也不是删除(也就是说,隐式定义或默认默认构造函数),该对象是零初始化,然后如果它有一个非平凡的默认构造函数,则它是默认初始化;


请注意,只有零初始化,而不是默认初始化 a>。 P 的私人默认构造函数不会被调用。


T 是非联合类类型,所有基类和非静态数据成员都进行零初始化,并且所有填充都初始化为零位。构造函数(如果有)将被忽略。


如果您明确将其更改为默认初始化,则会出现访问冲突错误。

  Logger():BASE {P()} {} //错误:调用类的一个私有构造函数< Logger> :: P 
/ / ~~

简化演示

  class X {X()= default; }; 

int main()
{
X x1 {}; // fine
X x2; //错误:调用类'X'的私有构造函数
}

LIVE



解决方案

您可以提供一个用户定义的默认构造函数,它是一个非平凡的构造函数,用于更改值初始化的行为。

  template< typename T> 
class SingletonBase {
protected:
class P {
friend class SingletonBase< T>
P(){} //用户定义的默认构造函数
};
public:
SingletonBase(P){}
};

class Logger:public SingletonBase< Logger> {
using BASE = SingletonBase< Logger> ;;
public:
Logger():BASE {P {}} {} //错误:调用类'SingletonBase< Logger> :: P'
}的私有构造函数;


In an attempt to answer another question, I came up with a scheme to force children of a CRTP base class to accept a particular type as a parameter in their constructors: make the parameter type's constructor private, assign the CRTP base class as a friend, and declare the parameter type as a parameter for the base class constructor as well.

However, when I tried to demonstrate that this scheme provided the desired protections via access violations, I found that even though the parameter type's constructor was private, the child class was able to construct it:

template <typename T>
class SingletonBase {
  protected: class P { friend class SingletonBase<T>; P() = default; };
  public:
     SingletonBase(P) {} 
};

class Logger: public SingletonBase<Logger> {
  using BASE = SingletonBase<Logger>;
  public:
    Logger() : BASE{P{}} {} // WHY NO ACCESS VIOLATION?
};

This compiles without error, even though I'd expect an access violation. Why?

解决方案

Does "friending" the base class in CRTP inheritance affect the child class as well?

No, of course not. Friendship is not inherited. To illustrate the issue,

Firstly, P::P() is a defaulted default constructor, it's a trivial default constructor.

Secondly, P{} is value initialization (since C++11),

(emphasis mine)

2) if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

Note it'll be only zero initialized here, not default initializated. The private default constructor of P won't be invoked at all.

If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.

If you change it to default initialization explicitly, you'll get the access violation error.

Logger() : BASE{P()} {} // error: calling a private constructor of class 'SingletonBase<Logger>::P
//               ~~

A simplified demonstration

class X { X() = default; };

int main()
{
    X x1{}; // fine
    X x2;   // error: calling a private constructor of class 'X'
}

LIVE

Solution

You can provide a user-defined default constructor, which is a non-trivial constructor, to change the behavior of value-initialization.

template <typename T>
class SingletonBase {
  protected: 
    class P { 
      friend class SingletonBase<T>; 
      P() {} // user-defined default constructor
    };
  public:
    SingletonBase(P) {} 
};

class Logger: public SingletonBase<Logger> {
  using BASE = SingletonBase<Logger>;
  public:
    Logger() : BASE{P{}} {} // error: calling a private constructor of class 'SingletonBase<Logger>::P'
};

这篇关于“亲友” CRTP继承中的基类是否也影响子类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆