问题
I have a templated class Rect with conversion constructor which allows conversion between Rect to Rect and vice a versa. But when compiling the code, the compiler gives an error stating the constructor can't access the protected members of the class. Here is code:
#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;
}
And here is the compilation error:
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
I want to solve this problem without using template specialization and making friend classes. As far as I know you can't declare constructors as friends. Any ideas?
Edit: I have made corrections to semantics. So the constructor I am trying to build is really a conversion constructor.
Edit2: Corrected the program.
回答1:
As K-ballo mentioned, Rect<int> and Rect<float> are different types, and do not have access to each others' private and protected members. You can explicitly allow this by adding the following template friend declaration to your class (like so):
template <typename U> friend class Rect;
Semantically, this means "for any type U, give the class Rect<U> access to my private and protected members" -- it is an outgoing permission grant from every Rect instantiation to every other Rect instantiation.
Note that this won't be necessary if you add accessors for width and height (as K-ballo suggests) -- then you can just use those accessors in the conversion constructor and forgo the friend definition entirely. I would prefer his solution over mine; I give mine merely as another possible option and to introduce to you a concept (friends, and specifically template friends) that you might not be familiar with.
回答2:
First thing you should know is that a template constructor is never a copy constructor. Second thing is that Rect<T> and Rect<U> where T != U are different unrelated classes, as unrelated as a std::string and an std::vector.
You should offer some way to access width and height, and your conversion constructors should use such access methods to create the new Rect.
来源:https://stackoverflow.com/questions/11001480/templated-conversion-constructor-fails-to-access-protected-data-members