2015-02-22 6 views
0

У меня есть базовый класс и производный класс. Я хочу, чтобы пользователь решил, когда free() память, выделенная обоими классами, и эти функции также будут вызываться деструкторами классов.Функция базового класса вызывается дважды

Однако этот подход заставляет функцию базового класса free() вызываться дважды, первый раз из производного класса free(), а второй раз из базового деструктора.

class Base 
{ 
public: 
    Base() { 
     _baseVal = new int(4); 
     cout << "base constructor\n"; 
    } 

    virtual void free() 
    { 
     if(_baseVal) { 
      delete _baseVal; 
      _baseVal = 0; 
     } 
     cout << "base free()\n"; 
    } 

    virtual ~Base() { 
     free(); 
    } 


private: 
    int *_baseVal; 
}; 

class Derived : public Base 
{ 
public: 
    Derived() { 
     _derivedVal = new int(10); 
     cout << "derived constructor\n"; 
    } 

    void free() 
    { 
     Base::free(); 

     if(_derivedVal) { 
      delete _derivedVal; 
      _derivedVal = 0; 
     } 
     cout << "derived free()\n"; 
    } 

    ~Derived() { 
     free(); 
    } 


private: 
    int *_derivedVal; 
}; 


int main() 
{ 
    Base *der = new Derived; 
    delete der; 

    system("pause"); 
    return 0; 
} 

Выход:

base constructor 
derived constructor 
base free() 
derived free() 
base free() 

Есть ли способ для этого подхода, который не заставит базу free() называться дважды?

+1

Не вызывайте 'Base :: free()' из 'Derived :: free()'. – juanchopanza

+0

Но что делать, если пользователь хочет использовать экземпляр? Возможно, перераспределите память целых чисел. Я не писал функцию 'allocate()', чтобы вещи не усложнялись. – Pilpel

+0

продолжать использовать его после уничтожения ?? –

ответ

1

Деструктор не вызывается дважды, но Base::free() вызывается дважды. Разница важна, потому что последняя - ваш собственный метод класса. Деструктор вызывается компилятором и вызывается один раз и только один раз.

Когда объект Derived выходит из сферы действия, сначала вызывается его собственный деструктор. В поле "Derived::~Derived" вы звоните, Derived::free(). Первое, что вы там делаете, - это позвонить Base::free(). Затем вы обрабатываете остальную логику производного класса. Когда часть Derived была очищена, выполняется деструктор для части Base, которая сама по себе вызывает Base::free().

В принципе у вас нет проблем, потому что вы убедились, что Base::free() ничего не делает, если он уже запущен (установив _baseVal на нулевой указатель). Вы можете избежать этого, удалив звонок до Base::free() от Derived::free(), так как деструктор Base гарантирует, что Base::free() будет запускаться хотя бы один раз.