可能不是最明智的选择,而是将Vertex<T, N>
类建模为抽象Vertex2<T>
,Vertex3<T>
和Vertex4<T>
实现,提供基本访问。它的结构如下:
template<typename T, unsigned N>
class _Vertex {
const unsigned _size = N;
T _data[N];
public:
inline _Vertex() : _data() {};
inline T const& operator[](int pos) const { return _data[pos]; }
inline T & operator[](int pos) { return _data[pos]; }
};
假设我想将Vertex2<T>
实现为Vertex<T, 2>
,并提供x
和y
等别名。最合适的方法是添加以下功能:
inline T const& x() const { return (*this)[0]; }
inline T & x() { return (*this)[0]; }
对于我想要添加的每个属性或别名,都会重复此操作。这不是一个糟糕的设计,但用法证明是棘手的,因为v
类型为Vector2<float>
,v.x() = 1.0f
不如v.x = 1.0f
友好。
有没有办法提供更清晰,更友好的别名?
我的主要想法是“滥用”内存布局,相应地提供对_data[i]
的访问权限,但我不知道从哪里开始。
这个问题是基于我为一个分配提供的vertex.h
头文件的“重新想象”,因此这与家庭作业有关,但我可以向你保证最终不会。这只是我的好奇心让我不做功课!
答案 0 :(得分:1)
我穿上我的长袍和Yakk帽子。
operator->*
在C ++中显然未被充分利用。我们可以重载以我们选择的标记类型,使其看起来像成员访问。这是一个简化的例子:
template <size_t I> struct index_t { };
constexpr index_t<0> x{};
constexpr index_t<1> y{};
struct Vector {
int data[2];
template <size_t I>
int& operator->*(index_t<I> ) { return data[I]; }
int& operator[](size_t idx) { return data[idx]; }
};
有了这个,我们可以做到:
int main()
{
Vector v{1, 2};
std::cout << v.data[0] << ' ' << v.data[1] << '\n'; // 1 2
v->*x = 42;
v->*y = 17;
std::cout << v.data[0] << ' ' << v.data[1] << '\n'; // 42 17
}
那就是说,不要这样做。 C ++没有属性。执行此操作的正确方法只是命名返回左值引用的函数:
int& x();
int& y();
它可能不像v.x
那样“好”,但它可以完成工作,而无需在课程中添加额外的成员。
答案 1 :(得分:0)
v.x = 2.f
不是OOP / C ++成员访问方式。最好使用像t = v.x()
和v.x( t )
这样的get / set函数。
可以使用以下方法来破坏数据封装:
template< class T >
class Vertex2 : private Vertex< T, 2 >
{
public:
T & x;
T & y;
Vertex2(): Vertex< T, 2 >(), x((*this)[0]), y((*this)[1]) {}
};
这不提供const
访问权限,但如果你想v.x =
,你可能不太关心这些事情。不幸的是,你可能会被两个引用的额外内存所困扰。