0

我即将为我正在编写的库“创建”我自己的矢量类。我不会真正从头开始创建矢量类,而只是std::vector用作父类并向派生的矢量类添加一些东西。

现在,也就是说,我需要一些建议。我的问题是:

1)调用我的派生类vector(当然是在另一个命名空间内)是一个坏主意吗?在这种情况下我会遇到什么样的冲突?

2)我想重载数学运算符,以便能够添加向量、将向量乘以常量等。这实际上是我决定在std::vector. 但是,我可以std::vector直接重载数学运算符并省去创建(又一个......)向量类的麻烦——但这是个坏主意吗?

3) 我非常想从 继承构造函数std::vector,但是在没有编译器错误的情况下完成这项工作时遇到了很多麻烦。有人可以为我提供一个具体的例子,向我展示如何做到这一点?

谢谢!

4

3 回答 3

3

我会劝阻你不要这样做。如果您需要一个新容器,只需嵌入(或私下继承)std::vector<>而不是公开继承。

关于您的问题:

1)调用我的派生类向量(当然是在另一个命名空间内)是不是一个坏主意?在这种情况下我会遇到什么样的冲突?

只要您和您的任何客户都不会std通过指令同时导入名称空间和您的名称空间using,我看不出这有什么特别的问题。

2) 我想重载数学运算符,以便能够添加向量、将向量乘以常数等。这实际上是我决定在 std::vector 之上构建一个向量类的原因。但是,我可以直接重载 std::vector 的数学运算符,省去创建(又一个......)向量类的麻烦——但这是个坏主意吗?

是的,这是个坏主意。如果您为 创建了数学运算符的重载,则std::vector无法在std::vector所属的命名空间中创建它们。通过 ADL,operator +即使不合适,也可能在该名称空间中找到一个全局变量。如果是这种情况,你operator +甚至不会被查找,你会得到一个编译器错误。

3) 我非常想从 std::vector 继承构造函数,但是在没有编译器错误的情况下完成这项工作时遇到了很多麻烦。有人可以为我提供一个具体的例子,向我展示如何做到这一点?

在 C++11 中,您可以使用继承的构造函数。例如:

#include <vector>

template<typename T, typename Allocator = std::allocator<T>>
class myvector : public std::vector<T, Allocator>
{
    using typename std::vector<T, Allocator>::vector;
};

#include <iostream>

int main()
{
   std::vector<int> vi { 1, 2, 3, 4, 5};

   // Uses inherited constructor
   myvector<int> v(vi.begin(), vi.end());

   for (auto i : v) { std::cout << i << " "; };
}

这是一个使用 GCC 4.8.0 (beta) 的活生生的例子,它支持继承的构造函数。

于 2013-03-03T20:23:15.917 回答
2

首先,请注意,如果您愿意,您可以混淆您的继承。使用private继承,然后使用 with语句使所有功能vector可用。using它仍然是相当多的类型,因为vector它有很多,但它不像显式委派每个函数那样多,它可以防止通常对继承的反对,人们会不小心分割你的派生类和/或使用删除它没有虚拟析构函数时类型错误。并不是说任何人都应该删除vector

1) 从命名空间使用相同的名称std本质上不是问题(毕竟这就是命名空间的用途),但有时可能会让读者感到困惑。他们可能只是假设你在某个地方做过using std::vector;。这是他们自己的错,但如果你能想出另一个合适的名字,那么惩罚你的读者的错误将没有任何好处。

2)您可以重载标准类的运算符,但不能在std命名空间中。这留下了一个问题,您应该在什么范围内重载它们。通常,您不想将内容放入头文件中的全局范围内,但您可以例如将它们放入名为的命名空间中vector_arithmetic,然后放入using namespace vector_arithmetic;您从中使用的每个范围内想使用它们。仅仅因为你可以这样做并不意味着它是明智的——读者希望知道哪些运算符可用于常见的类,例如vector,并且更改可用运算符的集合可能会吓到和打扰他们。

3)如果你没有C++11构造函数继承,你就不能继承构造函数。相反,您需要费力地编写自己的构造函数,这些构造函数采用正确的参数并在初始化列表中调用适当的基类构造函数。标准(或其他文档)将告诉您所需的所有构造函数签名。请特别注意模板化构造函数,并注意 C++03 和 C++11 中的构造函数不同。

最后,考虑只写一些自由函数:

template <typename T>
T sequence_add(const T &lhs, const T &rhs) {
    if (rhs.size() != lhs.size()) throw std::logic_error("size mismatch");
    T result(lhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(), result.begin(),
        std::plus<typename T::value_type>()
    );
    return result;
}

std::vector<int> i,j;
std::vector<int> k = sequence_add(i,j);

等等。如果运算符重载会引起混乱,那么它们通常不值得。

于 2013-03-04T00:29:44.743 回答
1

1)在您的命名空间下编写您自己的向量。但是,尽量不要从 STL 派生。

2,3)忘记std::vector,写你自己的方法和运算符。

此外,您可以包装std::vector新类并编写接口来操作它。

于 2013-03-03T20:20:09.880 回答