Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么在C++;?_C++_Destructor_Pure Virtual - Fatal编程技术网

C++ 为什么在C++;?

C++ 为什么在C++;?,c++,destructor,pure-virtual,C++,Destructor,Pure Virtual,我知道需要一个虚拟析构函数。但是为什么我们需要一个纯粹的虚拟析构函数呢?在C++文章中,作者提到了在想抽象类时使用纯虚析构函数。p> 但我们可以通过将任何成员函数作为纯虚函数来抽象类 所以我的问题是 什么时候我们才能真正使析构函数成为纯虚拟的?谁能给出一个好的实时示例 当我们创建抽象类时,使析构函数也是纯虚拟的是一种好做法吗?如果是,为什么 1) 当需要派生类进行清理时。这是罕见的 2) 不,但是你希望它是虚拟的 允许使用纯虚拟析构函数的真正原因可能是,禁止它们意味着在语言中添加另一条规则,并且

我知道需要一个虚拟析构函数。但是为什么我们需要一个纯粹的虚拟析构函数呢?在C++文章中,作者提到了在想抽象类时使用纯虚析构函数。p> 但我们可以通过将任何成员函数作为纯虚函数来抽象类

所以我的问题是

  • 什么时候我们才能真正使析构函数成为纯虚拟的?谁能给出一个好的实时示例

  • 当我们创建抽象类时,使析构函数也是纯虚拟的是一种好做法吗?如果是,为什么

  • 1) 当需要派生类进行清理时。这是罕见的

    2) 不,但是你希望它是虚拟的

  • 允许使用纯虚拟析构函数的真正原因可能是,禁止它们意味着在语言中添加另一条规则,并且没有必要使用此规则,因为允许使用纯虚拟析构函数不会产生任何不良影响

  • 不,简单的旧虚拟就足够了

  • 如果使用虚拟方法的默认实现创建对象,并希望在不强制任何人重写任何特定方法的情况下将其抽象化,则可以将析构函数设置为纯虚拟。我不认为这有什么意义,但这是可能的

    请注意,由于编译器将为派生类生成隐式析构函数,如果该类的作者不这样做,则任何派生类都将为抽象类。因此,在基类中使用纯虚拟析构函数不会对派生类产生任何影响。它只会使基类抽象(感谢您的评论)

    我们还可以假设,每个派生类可能都需要特定的清理代码,并使用纯虚拟析构函数作为编写一个析构函数的提醒,但这似乎是人为的(而且是非强制的)


    注意:析构函数是唯一一种方法,即使它是纯虚拟的也有一个实现来实例化派生类(是的,纯虚拟函数可以有实现)


    如果要创建抽象基类,请执行以下操作:

    • 无法实例化的(是的,这与术语“抽象”是多余的!)
    • 但是需要虚拟析构函数行为(您打算携带指向ABC的指针,而不是指向派生类型的指针,并通过它们进行删除)
    • 但<强>不需要其他方法的其他虚拟调度< /强>行为(也许没有其他方法)?考虑一个简单的保护“资源”容器,它需要一个构造函数/析构函数/赋值,而不是其他很多东西)
    …通过使析构函数为纯虚拟并为其提供定义(方法体),最容易使类抽象

    对于我们假设的ABC:


    您可以保证它不能被实例化(即使是在类本身内部,这就是为什么私有构造函数可能不够用),您可以为析构函数获得所需的虚拟行为,并且您不必找到另一个不需要虚拟分派的方法并将其标记为“virtual”.

    抽象类所需的只是至少一个纯虚函数。任何功能都可以;但事实上,析构函数是任何类都会有的,所以它总是作为候选者存在。此外,使析构函数纯虚拟(而不仅仅是虚拟)除了使类抽象之外,没有任何行为副作用。像这样的许多样式指南建议一致使用纯虚拟析构函数来指示类是抽象的,除非它提供了一个一致的位置,阅读代码的人可以查看该类是否是抽象的。

    如果您想停止实例化基类而不对已存在的类进行任何更改实现并测试派生类,则在基类中实现纯虚拟析构函数

    我们需要使析构函数虚拟化,因为如果我们不使析构函数虚拟化,那么编译器只会破坏基类的内容,n所有派生类都将保持不变,因为编译器不会调用除基类之外的任何其他类的析构函数。

    你问了一个例子,我相信下面提供了一个纯虚拟析构函数的理由。我期待着答复这是否是一个好的理由

    我不希望任何人能够抛出
    error\u base
    类型,但是异常类型
    error\u oh\u shucks
    error\u oh\u blast
    具有相同的功能,我不想写两次。pImpl的复杂性对于避免将
    std::string
    暴露给我的客户机是必要的,而使用
    std::auto_ptr
    则需要复制构造函数

    public标头包含异常规范,客户端可以使用这些规范来区分my library引发的不同类型的异常:

    // error.h
    
    #include <exception>
    #include <memory>
    
    class exception_string;
    
    class error_base : public std::exception {
     public:
      error_base(const char* error_message);
      error_base(const error_base& other);
      virtual ~error_base() = 0; // Not directly usable
    
      virtual const char* what() const;
     private:
      std::auto_ptr<exception_string> error_message_;
    };
    
    template<class error_type>
    class error : public error_base {
     public:
       error(const char* error_message) : error_base(error_message) {}
       error(const error& other) : error_base(other) {}
       ~error() {}
    };
    
    // Neither should these classes be usable
    class error_oh_shucks { virtual ~error_oh_shucks() = 0; }
    class error_oh_blast { virtual ~error_oh_blast() = 0; }
    
    exception_string类保持私有,从我的公共接口隐藏std::string:

    // exception_string.h
    
    #include <string>
    
    class exception_string {
     public:
      exception_string(const char* message) : message_(message) {}
    
      const char* get() const { return message_.c_str(); }
     private:
      std::string message_;
    };
    

    这里我想告诉大家什么时候需要虚拟析构函数,什么时候需要纯虚拟析构函数

    class Base
    {
    public:
        Base();
        virtual ~Base() = 0; // Pure virtual, now no one can create the Base Object directly 
    };
    
    Base::Base() { cout << "Base Constructor" << endl; }
    Base::~Base() { cout << "Base Destructor" << endl; }
    
    
    class Derived : public Base
    {
    public:
        Derived();
        ~Derived();
    };
    
    Derived::Derived() { cout << "Derived Constructor" << endl; }
    Derived::~Derived() {   cout << "Derived Destructor" << endl; }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        Base* pBase = new Derived();
        delete pBase;
    
        Base* pBase2 = new Base(); // Error 1   error C2259: 'Base' : cannot instantiate abstract class
    }
    
    类基
    {
    公众:
    Base();
    virtual~Base()=0;//纯虚拟,现在没有人可以直接创建基对象
    };
    
    Base::Base(){cout从我读到的对你问题的回答中,我无法推断出一个实际使用纯虚拟析构函数的好理由。例如,以下理由根本无法说服我:

    允许使用纯虚拟析构函数的真正原因可能是,禁止它们意味着在语言中添加另一条规则,并且没有必要使用此规则,因为允许使用纯虚拟析构函数不会产生任何不良影响

    在我看来,纯粹的虚拟德
    // exception_string.h
    
    #include <string>
    
    class exception_string {
     public:
      exception_string(const char* message) : message_(message) {}
    
      const char* get() const { return message_.c_str(); }
     private:
      std::string message_;
    };
    
    #include "error.h"
    
    throw error<error_oh_shucks>("That didn't work");
    
    // client.cpp
    
    #include <error.h>
    
    try {
    } catch (const error<error_oh_shucks>&) {
    } catch (const error<error_oh_blast>&) {
    }
    
    class Base
    {
    public:
        Base();
        virtual ~Base() = 0; // Pure virtual, now no one can create the Base Object directly 
    };
    
    Base::Base() { cout << "Base Constructor" << endl; }
    Base::~Base() { cout << "Base Destructor" << endl; }
    
    
    class Derived : public Base
    {
    public:
        Derived();
        ~Derived();
    };
    
    Derived::Derived() { cout << "Derived Constructor" << endl; }
    Derived::~Derived() {   cout << "Derived Destructor" << endl; }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        Base* pBase = new Derived();
        delete pBase;
    
        Base* pBase2 = new Base(); // Error 1   error C2259: 'Base' : cannot instantiate abstract class
    }
    
    struct IParams
    {
        IParams(const ModelConfiguration& aModelConf);
        virtual ~IParams() = 0;
    
        void setParameter(const N_Configuration::Parameter& aParam);
    
        std::map<std::string, std::string> m_Parameters;
    };
    
    struct NumericsParams : IParams
    {
        NumericsParams(const ModelConfiguration& aNumericsConf);
        virtual ~NumericsParams();
    
        double dt() const;
        double ti() const;
        double tf() const;
    };
    
    struct PhysicsParams : IParams
    {
        PhysicsParams(const N_Configuration::ModelConfiguration& aPhysicsConf);
        virtual ~PhysicsParams();
    
        double g()     const; 
        double rho_i() const; 
        double rho_w() const; 
    };
    
     virtual ~Fruit() = 0;  // pure virtual 
     Fruit::~Fruit(){}      // destructor implementation
    
    class Printable {
      virtual void print() const = 0;
      // virtual destructor should be here, but not to confuse with another problem
    };
    
    class Printer {
      void queDocument(unique_ptr<Printable> doc);
      void printAll();
    };
    
    class Destroyable {
      virtual ~Destroyable() = 0;
    };
    
    class PostponedDestructor {
      // Queues an object to be destroyed later.
      void queObjectForDestruction(unique_ptr<Destroyable> obj);
      // Destroys all already queued objects.
      void destroyAll();
    };