C++中的友元模版

友元在C++中意味着不好的设计,因忽略访问属性的限制,破坏了封装性。我却很喜欢这个特性。
特别说明,这个特性适合库作者,一般的使用者可能意义不大,尤其是作为代码的搬运工。
在非模版的设计中,有些时候,在写目标类的时候尚不能确定那个类成为友元类,只能后期增加友元类的声明,这就导致目标类的代码不能封闭。模版可以解决这个问题,将友元类的设置延后到编译阶段。
比如有个日志类,有私有的方法和私有数据成员。想要直接访问私有数据成员,除了用公开的get/set外,就只能用友元了。通过模版,这个myLog类的代码就能封闭了。

template 
class myLog
{
    friend T;
    std::string str;
    void print()
    {
        std::cout << str << std::endl;
    }
public:
    myLog() = default;
};
class writeDataToLog
{
private:
    using Log = myLog;
    Log _log;
public:
    void setval(std::string data) {
        _log.str = data;
    }
    void print()
    {
        _log.print();
    }
};

重要的就是friend T;这一句,在writeDataToLog里就可以直接变身为myLog的友元,调用私有的变量和函数。
如果T是普通类型如int,double等,这一句是被编译器忽略的,不会有副作用。所以如果定义一个别名来直接使用类型无关的myLog:

using myLog_t = myLog;
myLog_t log;

如果还不能说明友元模版的必要性,我们看看另外一个例子(重点在第14行),这是个使用引用计数的智能指针的片段:

template
class SmartPointer
{
   T* pointer = nullptr;
   ReferenceCount* refcount = nullptr;
  //友元模板,让其它类型的智能指针可以直接访问私有变量
  template
  friend class SmartPointer;
  //...     
  //有继承关系的构造,向上转换,U继承自T
  template>>
  SmartPointer(SmartPointer const& other)
  {
    if (pointer = other.pointer, refcount = other.refcount)  //友元模板的设置才能访问other的私有变量
    {
        refcount->increment();
    }
  }
  //...
}

如果像让不同的每个myLog的实例类都能互相访问私有数据,则可以这么做:

template 
class myLog
{
    //...
    template
    friend class myLog;
    //...
}

这样,myLog家族类之间就没有秘密了。仔细琢磨,这挺神奇的。

你可能感兴趣的:(C++中的友元模版)