是"友情" CRTP继承中的基类也会影响子类?

时间:2016-09-10 07:45:39

标签: c++ inheritance private friend crtp

attempt to answer another question中,我想出了一个方案来强制CRTP基类的子类在其构造函数中接受特定类型作为参数:make参数类型的构造函数{{1} ,将CRTP基类指定为"@angular/router": "3.0.0-rc.2", "rxjs": "5.0.0-beta.11", "zone.js": "^0.6.17" ,并将参数类型声明为基类构造函数的参数。

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

private

compiles without error,即使我预计会发生访问冲突。为什么?

2 个答案:

答案 0 :(得分:2)

  

CRTP继承中的基类“友好”是否也会影响子类?

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

首先,P::P()是默认的默认构造函数,它是trivial default constructor

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

(强调我的)

  

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

请注意,此处仅zero initialized,而不是default initializated。 <{1}}的私有默认构造函数根本不会被调用。

  

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

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

T

简化演示

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

LIVE

<强>解决方案

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

class X { X() = default; };

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

答案 1 :(得分:0)

您所做的与您的friend声明无关!

如果您删除了friend代码编译也没问题!

这是因为空类的默认构造函数是public:

来自C ++ 11标准:

  

如果类X没有用户声明的构造函数,则没有参数的构造函数被隐式声明为默认值。隐式声明的默认构造函数是其类的内联公共成员。

如果您没有这样的默认构造函数:

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

    public:
        SingletonBase(P) {}
};

class Logger: public SingletonBase<Logger>
{
    using BASE = SingletonBase<Logger>;

    public:
    Logger() : BASE(P{1}) {} // WHY NO ACCESS VIOLATION?
};

您将获得&#34;访问&#34;违规行为,您发现friend无效!:

main.cpp: In constructor 'Logger::Logger()':
main.cpp:10:17: error: 'SingletonBase<T>::P::P(int) [with T = Logger]' is private
                 P(int){ }
                 ^
main.cpp:22:28: error: within this context
         Logger() : BASE(P{1}) {} // WHY NO ACCESS VIOLATION?