【问题标题】:Implementing a virtual destructor in C++在 C++ 中实现虚拟析构函数
【发布时间】:2013-07-01 22:01:58
【问题描述】:

我开始学习 c++,但我被困在析构函数中。我们需要实现一个向量,这就是我目前所拥有的。

#include<string.h>
#include<cassert>
#include<iostream>

using namespace std;
template<class T>
class Vector {
    template<class U> friend ostream& operator<<(ostream&, const Vector<U>&);
private:
    T* data;
    unsigned len;
    unsigned capacity;
public:
    Vector(unsigned = 10);
    Vector(const Vector<T>&);
    virtual ~Vector(void);
    Vector<T>& operator =(const Vector<T>&);
    bool operator==(const Vector<T>&);
    T& operator[](unsigned);
};

//PROBLEM! 
template <class T>
~ Vector() {
    delete data;

}

template<class T>
Vector<T>::Vector(unsigned int _capacity)
{
    capacity = _capacity;
    len = _capacity;
    data = new T[_capacity];
}

template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
    len = v.len;
    capacity = v.capacity;
    data = new T[len];
    for (unsigned int i = 0; i < len; i++)
        data[i] = v.data[i];
}



template<class T>
Vector<T> & Vector<T>::operator = (const Vector<T> & v)
{
    delete[ ] data;
    len = v.len;
    capacity = v.capacity;
    data = new T [len];
    for (unsigned int i = 0; i < len; i++)
        data[i] = v.data[i];
    return *this;
}

template<class T>
bool Vector<T>::operator == (const Vector<T> & v)
{
    bool check = true;
    check &= (len == v.len);
    if (!check) return false;
    check &= (capacity == v.capacity);
    if (!check) return false;
    for (unsigned int i = 0; i < len; i++) {
        check &= (data[i] == v.data[i]);
        if (!check) return false;

    }
    return true;
}

template<class T>
T& Vector<T>::operator[](unsigned int index)
{
    return data[index];
}

接口给定了,我需要实现它。但这与 C 和 Java 有很大的不同,我有点迷茫。


在第二个练习中,我们需要使用 a) 以前的 Vector 实现作为派生类和 b) Vector 作为组合类来实现类似的东西,所以也许我们会在其中一种方法中使用虚拟析构函数?

void testAssociativeArray() { 
AssociativeArray<String, int> table;
 table["abc"] = 15;
 table["jkl"] = 12;
 table["xyz"] = 85;
 assert(table["jkl"], 12);
 }

template<class P, class Q>
class Pair {
P p;
Q q; public:
      Pair(const P& _p = P(), const Q& _q = Q()): p(_p), q(_q) {}
      P& objectP() {return p;}
      Q& objectQ() {return q;}
};

【问题讨论】:

标签: c++ virtual-destructor


【解决方案1】:

首先,为什么你认为析构函数应该是virtual?你在使用多态性吗?

其次,您在阵列中错误地使用了delete

自从你使用:

data = new T[length];

您必须使用数组语法:

delete [] data;

第三,你需要把命名空间放在你所有的类函数定义的前面:

template <class T>
Vector<T>::~Vector()
{
    delete [] data;
}

为了您的信息,您声明析构函数是这样的......

virtual ~Vector(void);

正如我所提到的,virtual 是不必要的,除非您以多态方式将此类用作基类或派生类。有关何时需要使用 virtual 析构函数的更多信息,请查看 answer to this question

另外,参数中的void也是不必要的。这在旧的 C 标准中曾经是必需的,但在 C++ 中却没有。

你应该可以这样声明:

~Vector();

如果您使用与Vector&lt;T&gt;has-a 关系来定义AssociativeArray&lt;P,Q&gt;,那么您可以简单地使类包含Vector&lt;Pair&lt;P,Q&gt; &gt;。在这种情况下,不需要声明 virtual 方法,但仍然可以使用 - 需要一些额外的开销。

如果您使用与Vector&lt;Pair&lt;P,Q&gt; &gt;is-a 关系来定义AssociativeArray&lt;P,Q&gt;,那么您应该在Vector&lt;T&gt; 中定义一些virtual 方法,包括virtual 析构函数。

virtual 方法的使用仅在通过指针和引用以多态方式使用对象时才重要。见this page

AssociativeArray<String,Int>* myDerivedMap = new AssociativeArray<String,Int>();
delete myDerivedMap; //NO virtual methods necessary here. using a pointer to derived class

Vector<Pair<String,Int> >* myBaseMap = new AssociativeArray<String,Int>();
delete myBaseMap; //virtual methods ARE necessary here. using a pointer to base class

【讨论】:

  • 您能否更深入地了解virtual/non-virtual 部分?
  • 我链接到另一个问题,该问题以非常直接的方式解释了这一点。
  • 在派生类中使析构函数为虚拟不会使基析构函数成为虚拟,因此通过基类指针析构派生类仍然不会调用派生析构函数。因此,对于任何有最小机会被继承的类,通常将析构函数声明为 virtual 是有意义的。
  • 另外,如果基类有虚析构函数,派生类中的析构函数就不需要声明为虚了。这种虚拟是自动继承的。
  • @TilmanVogel - “对于任何最有可能被继承的类”:不,对于任何被设计派生的类。不要增加开销以支持可能的误用。
【解决方案2】:
template<class T> 
Vector<T>::~Vector()
{
    delete [] data;
}

请注意,您必须使用delete [] 而不是delete

【讨论】:

    【解决方案3】:

    应该是

    template <class T>
    Vector<T>::~Vector() {
        delete[] data;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-12
      • 1970-01-01
      • 1970-01-01
      • 2012-04-18
      • 2017-05-31
      • 2016-08-14
      • 1970-01-01
      • 2010-10-24
      • 2018-11-26
      相关资源
      最近更新 更多