模板化转换构造函数无法访问受保护的数据成员

时间:2012-06-12 17:12:45

标签: c++ templates constructor

我有一个带有转换构造函数的模板化类Rect,它允许在Rect和Rect之间进行转换,反之亦然。但是在编译代码时,编译器会给出一个错误,指出构造函数无法访问类的受保护成员。 这是代码:

#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

template< typename T >
class Rect{
protected:
  T width, height;
public:
  Rect(T a, T b){
    width = a;
    height = b;
  }
  template< typename U >
  Rect(Rect<U> const &r){
    width = r.width;
    height = r.height;
  }
  int area(){
    return width*height;
  }
};

int main(){
  Rect<int> a(3,4);
  Rect<float> b(a);
  cout<<b.area()<<endl;
}

这是编译错误:

test.cpp: In constructor ‘Rect<T>::Rect(const Rect<U>&) [with U = int, T = float]’:
test.cpp:28:18:   instantiated from here
test.cpp:10:7: error: ‘int Rect<int>::width’ is protected
test.cpp:18:5: error: within this context
test.cpp:10:14: error: ‘int Rect<int>::height’ is protected
test.cpp:19:5: error: within this context

我想在不使用模板专业化和制作朋友类的情况下解决此问题。据我所知,你不能将构造函数声明为朋友。有什么想法吗?

编辑:我对语义进行了更正。所以我试图构建的构造函数实际上是一个转换构造函数。

编辑2:更正了该计划。

2 个答案:

答案 0 :(得分:4)

您应该知道的第一件事是模板构造函数永远不是复制构造函数。第二件事是Rect<T>Rect<U>其中T != U是不同的无关类,与std::stringstd::vector无关。

您应该提供一些方法来访问widthheight,而您的转换构造函数应该使用此类访问方法来创建新的Rect

答案 1 :(得分:3)

正如K-ballo所提到的,Rect<int>Rect<float>是不同的类型,并且无法访问彼此的私人和受保护成员。您可以通过向类(like so)添加以下模板好友声明来明确允许此操作:

template <typename U> friend class Rect;

从语义上讲,这意味着“对于任何类型U,为类Rect<U>提供对我的私有和受保护成员的访问权限” - 这是从每个Rect实例化到的传出权限授予每隔一个Rect实例化。

请注意,如果您为widthheight添加访问器(如K-ballo建议的那样),则无需执行此操作 - 然后您可以在转换构造函数中使用这些访问器并放弃朋友定义完全。我宁愿他的解决方案超过我的;我只是作为另一种可能的选择给我,并向你介绍一个你可能不熟悉的概念(朋友,特别是模板朋友)。