简体   繁体   English

C ++:带有成员的抽象类中的纯虚析构函数

[英]C++: Pure virtual destructor in abstract class with members

I've just started learning C++ and stumbled across this problem.. I've written this abstract class with pure virtual destructor: 我刚开始学习C ++并偶然发现了这个问题。我用纯虚析构函数编写了这个抽象类:

#ifndef ANIMAL
#define ANIMAL
#include <string>
using namespace std;

class Animal {
public:
    Animal();
    virtual ~Animal() = 0;
    Animal(string name, int age);
    virtual string says() = 0;
    void setName(string name);
    void setAge(int age);
    string getName() const;
    int getAge() const;

private:
    int _age;
    string _name;
};
inline Animal::~Animal() { }

Created dynamically and destroyed like this... 像这样动态创建并销毁......

Animal** animalArray = new  Animal*[10];
animalArray[0] = new Dog(name, age);
animalArray[1] = new Cat(name, age);
animalArray[2] = new Owl(name, age);

delete[] animalArray;

and I am left wondering if an Animal object is created dynamically and then destroyed, will the _age and _name members get destroyed properly since the destructor for Animal class is empty? 我想知道动物对象是否是动态创建然后销毁的,_age和_name成员是否会被正确销毁,因为Animal类的析构函数是空的? If so, why? 如果是这样,为什么?

Thanks :D 感谢:D

In the example you posted, you're actually not destroying everything correctly. 在您发布的示例中,您实际上并未正确销毁所有内容。 In the line 在线

delete[] animalArray;

you are deleting an array of Animal* s. 你正在删除一个Animal*的数组。 Note that this does not automatically destroy the things being pointed to! 请注意, 这不会自动销毁指向的东西! You would have to do: 你必须这样做:

for(int i = 0; i < 3; ++i)
    delete animalArray[i];
delete[] animalArray;

This destroys each element, then destroys the container. 这会破坏每个元素, 然后破坏容器。

Now, your actual question is asking whether the private member variables are going to be cleanly destroyed. 现在,您的实际问题是询问私有成员变量是否会被彻底销毁。 The answer is yes--after your destructor runs, any statically allocated variables' destructors will also be called by the compiler. 答案是肯定的 - 在析构函数运行之后,编译器也会调用任何静态分配的变量的析构函数。 It is their obligation to clean up after themselves. 他们有义务自己清理。 When you're doing polymorphism as in your example, the (empty) destructor Animal::~Animal will indeed be called. 当你在你的例子中做多态时,确实会调用(空)析构函数Animal::~Animal

Note that this carries the same warning as the code above: if you instead have 请注意,这与上面的代码具有相同的警告:如果你改为

string* _name;

that you dynamically allocate in the constructor (with new ), then the string* will be destroyed, but the pointed to string will not be. 你在构造函数中动态分配(使用new ),然后string*将被销毁,但指向的 string将不会被销毁。 So in that case, you would have to manually call delete to properly clean up. 因此,在这种情况下,您必须手动调用delete才能正确清理。

it will , destructor is not really destroy the object you created , it is called before the object being destroied, if you have not new something in constructor , there is no need for you to delete it. 它会,析构函数不会真正破坏你创建的对象,它会在被破坏的对象之前被调用,如果你在构造函数中没有新的东西,就没有必要删除它。

I try to finger out a sample to prove 我试着指出一个样本来证明

when using string(with a pointer member) object as member variable, its destructor will be called, even we do nothing in the class's destructor 当使用字符串(带有指针成员)对象作为成员变量时,它的析构函数将被调用,即使我们在类的析构函数中什么都不做

so I tried to used a user-defined String as object, so it is easy for us to write some log in the destructor. 所以我尝试使用用户定义的String作为对象,因此我们很容易在析构函数中编写一些日志。

it outputs: 它输出:

constructor is called
constructor is called
constructor is called
operator constructor is called
destructor is called
operator constructor is called
destructor is called
virtual ~Dog()
virtual ~Animal()
destructor is called

it show is when virtual ~Animal() is called , the string object'destructor in the Animal class is called. 它显示的是当调用virtual~Animal()时,调用Animal类中的字符串object'detructor。

we can change the string object to string*(using new in construtor) while still doing nothing in the destructor , and we will see the string's destructor is not called 我们可以将字符串对象更改为字符串*(在construtor中使用new),同时在析构函数中仍然无效,我们将看到字符串的析构函数未被调用

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

using namespace std;


class String{
public:
    String(const char *str = NULL);
    String(const String &str);
    ~String();
    String operator+(const String & str);
    String & operator=(const String &str);
    bool operator==(const String &str);
    int Length();
    friend ostream & operator<<(ostream &o,const String &str);
    String SubStr(int start, int end);
private:
    char * charArray;
};

String::String(const char *str)
{
    if(str == NULL){
        charArray=new char[1];
        charArray[0]='\0';
    }else{
        charArray=new char[strlen(str)+1];
        strcpy(charArray,str);
    }
    std::cout<< "constructor is called" << std::endl;
}
String::String(const String &str)
{
    std::cout<< "constructor is called" << std::endl;
    charArray = new char[strlen(str.charArray)+1];
    strcpy(charArray,str.charArray);
}
String::~String()
{
    std::cout<< "destructor is called" << std::endl;
    delete [] charArray;
}
String String::operator+(const String &str)
{
    String res;
    delete [] res.charArray;
    res.charArray = new char[strlen(charArray)+strlen(str.charArray)+1];
    strcpy(res.charArray,charArray);
    strcpy(res.charArray+strlen(charArray),str.charArray);
    return res;
}
String & String::operator=(const String &str)
{
    if(charArray == str.charArray)
        return *this;
    delete [] charArray;
    charArray = new char[strlen(str.charArray)+1];
    strcpy(charArray,str.charArray);
    std::cout<< "operator constructor is called" << std::endl;
    return *this;
}
bool String::operator==(const String &str)
{
    return strcmp(charArray,str.charArray) == 0;
}
int String::Length()
{
    return strlen(charArray);
}
ostream & operator<<(ostream &o, const String &str)
{
    o<<str.charArray;
    return o;
}

String String::SubStr(int start, int end)
{
    String res;
    delete [] res.charArray;
    res.charArray = new char[end-start+1];
    for(int i=0; i+start<end; i++){
        res.charArray[i]=charArray[start+i];
    }
    res.charArray[end-start] = '\0';
    return res;
}


class Animal {
public:
    Animal();
    virtual ~Animal()=0;
    Animal(String name, int age);

public:
    int _age;
    String _name;
};
Animal::~Animal(){
    std::cout << "Animal::~Animal()" << std::endl;
}
Animal::Animal(String name, int age)
{
    this->_name = name;
    this->_age = age;
}

class Dog :public Animal
{
public:
    virtual ~Dog() {
         std::cout << "virtual ~Dog()" << std::endl;
    };
    Dog(String name, int age):Animal(name,age)
    {
        this->_name = name;
        this->_age = age;
    }
};

int main(){
   Animal* p = new Dog( String("dog"),1);
   delete p;
   return 0;
}

yes they will. 是他们会。 By making the Animal destructor virtual (or pure virtual in your case, doesn't matter regarding your question) you make sure that everything is properly destroyed when using Animal as a base class. 通过将Animal析构函数设置为虚拟(或者在您的情况下为纯虚拟,与您的问题无关),确保在使用Animal作为基类时,所有内容都已正确销毁。

The destructor of Animal will call the destructor for each of it's members in reverse initialization order (ie it will destroy _name first and _age afterwards) and thereby makes sure that everything is properly freed. Animal的析构函数将以反向初始化顺序为每个成员调用析构函数(即它将首先销毁_name并在之后销毁_age),从而确保一切都被正确释放。

According to Herb Sutter you cannot instantiate a class with a pure virtual destructor unless it also has a body. 根据Herb Sutter的说法,你不能用纯虚拟析构函数实例化一个类,除非它还有一个正文。 The reason is that any derived class will need to call that destructor after its own destructor is finished. 原因是任何派生类都需要在自己的析构函数完成后调用该析构函数。

We can verify this with at least one compiler: http://ideone.com/KcwL8W 我们可以使用至少一个编译器来验证这一点: http//ideone.com/KcwL8W

#include <string>

class Animal
{
    public:
    virtual ~Animal() = 0;

    std::string _name;
};

class Dog : public Animal
{
};

int main() {
    Animal* pet = new Dog;
    delete pet;
    return 0;
}

/home/abDVbj/cc8ghrZk.o: In function `Dog::~Dog()':
prog.cpp:(.text._ZN3DogD2Ev[_ZN3DogD5Ev]+0xb): undefined reference to `Animal::~Animal()'
/home/abDVbj/cc8ghrZk.o: In function `Dog::~Dog()':
prog.cpp:(.text._ZN3DogD0Ev[_ZN3DogD0Ev]+0x12): undefined reference to `Animal::~Animal()'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM