首页 文章

为什么给纯虚函数定义是有意义的?

提问于
浏览
20

斯科特在Effective C,3rd Edition,pg . 43要创建一个抽象类,我们只需要给它一个纯虚拟析构函数:

class AWOV {                  // AWOV = "Abstract w/o Virtuals"
public:
  virtual ~AWOV() = 0;        // declare pure virtual destructor
};

然后,他接着说有一个转折:我们必须为纯虚析构函数提供一个定义:

AWOV::~AWOW() {}              // definition of pure virtual dtor

我的问题是,通过指定 = 0 ,对于纯虚函数,我们说该函数不能对声明这个纯虚函数的类有任何定义 .

为什么在这里为纯虚拟析构函数提供定义(即使它是空的)是可以的?

5 回答

  • 10

    “我们说这个函数不能对声明这个纯虚函数的类有任何定义 . ”

    这不是纯虚拟的意思 . 纯虚拟仅意味着包含类不能被实例化(是抽象的),因此它必须被子类化,并且子类必须覆盖该方法 . 例如 . ,

    struct A {
        virtual ~A() = 0;
    };
    
    A::~A() {}
    
    struct B : A {};
    
    int main()
    {
        A a;  // error
        B b;  // ok
    }
    

    这里, B 析构函数是隐式定义的 . 如果它是另一种纯虚拟方法,则必须显式覆盖它:

    struct A {
        virtual void foo() = 0;
    };
    
    void A::foo() {}
    
    struct B : A {};
    
    int main()
    {
        B b;  // error
    }
    

    当基类必须是抽象的但仍提供某些默认行为时,需要为纯虚方法提供定义 .

    在析构函数的特定情况下,必须提供它,因为it will be called automatically当子类实例被销毁时 . 尝试使用没有定义的纯虚拟析构函数实例化类的子类的程序将不会传递链接器 .

  • 0

    使它成为纯粹的力派生(非抽象)类来实现自己的 .

    提供实现允许派生类调用基类行为(默认情况下析构函数会执行) .

  • 2

    有2例 .

    纯虚析构函数

    该案例由标准专门处理 .

    12.4析构函数[class.dtor]

    9)析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数 . 如果类具有带虚拟析构函数的基类,则其析构函数(无论是用户还是隐式声明)都是虚拟的 .

    析构函数的情况是不同的,因为所有析构函数都以构造的相反顺序在继承hierearchy中调用(假设正确删除),即使没有明确说明 . 因此,当对象被删除时,将调用基类析构函数 - 这就是它需要实现的原因 .

    纯虚方法

    这些与析构函数的不同之处在于它们不需要实现,也不需要实现 . 缺少需求的区别在于,当 Derived::foo() 被调用时,它不会自动调用 Base::foo() (不是它可以,因为它可以或不可以实现) .

    为什么要实现纯 virtual 方法取决于具体情况 . 我将纯说明符视为程序员的提示,而不是与逻辑相关 . 它告诉你 - 程序员 - that you should implement that method . 基类是否具有实现并不重要 .

    by specifiying = 0,对于纯虚函数,我们说该函数不能对声明这个纯虚函数的类有任何定义 .

    并不是的 . 你说派生的非抽象类必须覆盖该函数 . 这并不妨碍您自己实现它 .

  • 6

    这对于所有纯虚函数都不是必需的 . 一点也不 .

    这样,派生类将 still be forced to override the implementation ,但基类中将有一个默认实现 in case you need to call it . 并且's the case here - because you'正在处理析构函数:当一个派生对象被销毁时,它的析构函数被调用,并且它的基类析构函数也被调用 . 这就是为什么你需要 A::~A 的实现 .

  • 5

    通过使函数为纯虚拟,我们强制类的用户将该函数替换为派生类中的另一个函数 .

    仍然可以使用 BaseClass::myfunction(...) 调用基类函数

    现在,基类可能希望提供某些核心功能,如果派生类选择这样做,则可以使用这些功能 .

相关问题