c++ - 的try - 异常机制




你不应该从std:: vector继承 (8)

不公开从std :: vector继承的主要原因是没有虚拟析构函数,它可以有效地阻止你对多态后代的使用。 尤其是, 不允许 delete实际指向派生对象的std::vector<T>* (即使派生类不添加任何成员),但编译器通常无法警告您。

在这些条件下允许私有继承。 因此,我建议使用私有继承并从父级转发所需的方法,如下所示。

class AdVector: private std::vector<double>
{
    typedef double T;
    typedef std::vector<double> vector;
public:
    using vector::push_back;
    using vector::operator[];
    using vector::begin;
    using vector::end;
    AdVector operator*(const AdVector & ) const;
    AdVector operator+(const AdVector & ) const;
    AdVector();
    virtual ~AdVector();
};

您应该首先考虑重构您的算法以从它们正在操作的容器类型中抽象出来,并将它们留作免费的模板函数,正如大多数答复者所指出的那样。 这通常通过使算法接受一对迭代器而不是容器作为参数来完成。

好吧,这是很难承认,但我现在确实有一个强大的诱惑,从std::vector继承。

我需要大约10个定制的矢量算法,我希望它们是矢量的直接成员。 但自然我也想拥有std::vector接口的其余部分。 那么,作为守法的公民,我的第一个想法是在MyVector类中有一个std::vector成员。 但是接下来我将不得不手动重新提供所有std :: vector的接口。 输入太多。 接下来,我想到了私有继承,所以不用再提供方法,我会在公共部分编写一堆using std::vector::member的代码。 实际上这也很乏味。

在这里,我真的认为我可以简单地从std::vector公开继承,但是在文档中提供了一个警告,该类不应该多形地使用。 我认为大多数开发人员足以胜任,无论如何都不应该多形地使用它。

我的决定是绝对无理的吗? 如果是这样,为什么? 你能否提供一个替代方案,让其他成员实际上可以成为成员,但不会涉及重新输入vector的所有接口? 我对此表示怀疑,但如果可以的话,我会很开心。

此外,除了一些白痴可以写类似的事实

std::vector<int>* p  = new MyVector

使用MyVector有没有其他现实风险? 通过说实际的我放弃像想象一个函数,它需要一个指向向量的指针...

那么,我已经说明了我的情况。 我犯罪了。 现在取决于你原谅我还是不是:)


你希望完成什么? 只是提供一些功能?

C ++惯用的方法是只编写一些实现该功能的免费函数。 机会是你真的不需要一个std :: vector,专门用于你正在实现的功能,这意味着你实际上通过尝试从std :: vector继承来失去可重用性。

我强烈建议你看一下标准库和头文件,并冥想它们是如何工作的。


如果你正在考虑这一点,你显然已经杀死了你办公室的语言学生。 有了它们,为什么不这样做

struct MyVector
{
   std::vector<Thingy> v;  // public!
   void func1( ... ) ; // and so on
}

这将避开偶然向上注册MyVector类时可能出现的所有可能的失误,并且只需添加一点.v即可访问所有向量操作。


如果您遵循良好的C ++风格,虚拟函数的缺失不是问题,但切片 (请参阅https://.com/a/14461532/877329 )

为什么虚拟功能的缺失不是问题? 因为函数不应该尝试delete它接收的指针,因为它没有它的所有权。 因此,如果遵循严格的所有权策略,则不需要虚拟析构函数。 例如,这总是错误的(有或没有虚拟析构函数):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    delete obj;
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj); //Will crash here. But caller does not know that
//  ...
    }

相反,这将始终工作(有或没有虚拟析构函数):

void foo(SomeType* obj)
    {
    if(obj!=nullptr) //The function prototype only makes sense if parameter is optional
        {
        obj->doStuff();
        }
    }

class SpecialSomeType:public SomeType
    {
    // whatever 
    };

int main()
    {
    SpecialSomeType obj;
    doStuff(&obj);
//  The correct destructor *will* be called here.
    }

如果对象是由工厂创建的,工厂还应该返回一个指向正在工作的删除器的指针,因为工厂可能会使用自己的堆,应该使用该指针而不是delete 。 调用者可以获得它的share_ptrunique_ptr形式。 总之,不要delete你没有直接 new获得的东西。


我最近还从std::vector继承了,发现它非常有用,到目前为止我还没有遇到任何问题。

我的类是一个稀疏矩阵类,这意味着我需要将我的矩阵元素存储在某个地方,即在std::vector 。 我继承的原因是我有点懒得为所有方法编写接口,而且我通过SWIG将类连接到Python,其中已经有了std::vector良好接口代码。 我发现将这个接口代码扩展到我的类比从头开始编写新的接口代码更容易。

我用这种方法看到的唯一问题不是非虚拟析构函数,而是其他一些我想重载的方法,比如push_back()resize()insert()等。私有继承确实是一个很好的选择。

谢谢!


我认为应该百分之百盲目地遵循很少的规则。 这听起来像你给了它很多思考,并相信这是一条路。 所以 - 除非有人出于好的具体原因不这样做 - 我认为你应该继续你的计划。


是的,只要你小心不要做那些不安全的事情,这是安全的......我不认为我见过任何人使用新的载体,所以在实践中你可能会好起来的。 不过,这不是c ++中常见的习惯用法....

你能提供更多关于算法的信息吗?

有时候,你最终会走上一条设计道路,然后看不到你可能采用的其他路径 - 事实上,你声称需要用10个新算法向我发出警钟 - 是否真的有10个通用一个向量可以实现的算法,还是你想要创建一个既是通用矢量又包含特定应用函数的对象?

我当然不是说你不应该这样做,只是因为你提供的信息令人震惊,这使得我认为你的抽象可能有些问题,并且有更好的方法来实现你的目标想。


没有理由从std::vector继承,除非你想创建一个不同于std::vector ,因为它以自己的方式处理std::vector的定义的隐藏细节,或者除非有意识形态的原因,使用这种类的对象代替std::vector的。 然而,C ++标准的创建者并没有提供带有任何接口(以受保护成员的形式)的std::vector ,这样的继承类可以利用这些接口来以特定方式改进向量。 事实上,他们没有办法想到任何可能需要扩展或微调额外实现的特定方面,所以他们不需要考虑为任何目的提供任何此类接口。

第二个选项的原因可能只是意识形态,因为std::vector s不是多态的,否则无论是通过公共继承还是通过公共成员来公开std::vector的公共接口都没有区别。 (假设你需要在你的对象中保留一些状态,所以你不能逃脱自由函数)。 从不太可靠的音符和从意识形态的角度来看,似乎std::vector s是一种“简单的想法”,所以在意识形态上不同可能类的对象形式的任何复杂性都无济于事。





vector