派生类(向量):这是个坏主意吗?
derived class (vector): is this a bad idea?
我即将为我正在编写的库"创建"我自己的向量类。我不会真的从头开始创建一个向量类,但只是使用std::vector
作为父类,并添加一些东西到我的派生向量类。
话虽如此,我还是需要一些建议。我的问题是:
1)调用我的派生类vector
(在另一个命名空间内,当然)是一个坏主意吗?在这种情况下会有什么样的冲突?
2)我想重载数学运算符,以便能够添加向量,将向量乘以常量等。这实际上是我决定在std::vector
之上建立一个矢量类的原因。不过,我可以直接重载std::vector
的数学运算符,从而省去创建(又一个……)向量类的麻烦——但这是个坏主意吗?
3)我非常想继承std::vector
的构造函数,但我在没有编译器错误的情况下完成这一点有很多麻烦。有人能给我提供一个具体的例子,告诉我如何做到这一点吗?
谢谢!
我劝你不要那样做。如果您需要一个新的容器,只需嵌入(或从私有继承) std::vector<>
,而不是从它公开继承。
关于你的问题:
1)调用我的派生类向量(在另一个命名空间内,当然)是一个坏主意吗?在这种情况下会有什么样的冲突?
只要您和您的任何客户端都不会通过using
指令导入std
命名空间和您的命名空间,我不认为这有什么特别的问题。
2)我想重载数学运算符,以便能够添加向量,将向量乘以常量等。这实际上是我决定在std::vector之上构建vector类的原因。不过,我可以直接重载std::vector的数学运算符,从而省去了创建(又一个……)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)的实例,它支持继承构造函数。
首先,如果您愿意,请注意您可以混淆继承。使用private
继承,然后使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);
等等。如果操作符重载会引起混淆,那么它们通常是不值得的。
1)在您的命名空间下编写您自己的向量。但是,尽量不要从stl派生。
2,3)忘记std::vector
,编写自己的方法和操作符。
同样,您可以将std::vector
包装在您的新类中,并编写接口来操作它。
- 如何通过派生类函数更改基类中的向量
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 如何创建派生对象的向量?
- 将shared_ptr的向量复制到抽象基的派生类
- 基类到派生类的强制转换向量
- 创建基类指针的向量并将派生类对象传递给它(多态性)
- 有没有办法复制派生类指针的向量而不将其强制转换为基类?
- 无法将派生类存储在基类指针的向量中
- 在 c++ 中,如何使用向量调用派生类?
- 基类类型向量中的派生结构
- 按类型排序向量并按类型或派生类型搜索
- 替换派生对象向量中的对象"no matching function to call"
- 用于填充 Base 和派生对象的 shared_ptr 向量的函数模板
- 使用 shared_ptr 的派生类对象的向量
- 指向派生类的向量的指针
- 如何在另一个类的向量中调用派生类的析构函数
- 将抽象派生类对象存储在基类向量中
- 使用 boost::序列化将派生类指针序列化为向量时出现问题
- 如何从基类向量达到派生的类变量
- 向量派生类的复制构造函数