当我尝试以多态方式删除派生对象时(即:基类具有公共虚拟析构函数),为什么仍然会调用派生类私有析构函数?为什么范围分辨率私有无效。
class Base
{
protected:
Base() { cout << "Base constructor.\n"; }
public:
virtual ~Base() { cout << "Base destructor.\n"; }
};
class Derived :public Base
{
public:
Derived() { cout << "Derived constructor.\n"; }
private:
~Derived() { cout << "Derived destructor.\n"; }
};
int main()
{
Base *p = new Derived();
delete p;
}
输出:
Base constructor.
Derived constructor.
Derived destructor.
Base destructor.
答案 0 :(得分:3)
因为析构函数是按构造函数的相反顺序调用的,所以总是会调用虚析构函数。
如果要调用虚函数, private
无关。
正如我指出的那样:
Why would a virtual function be private?
ISO C ++ 1998标准版明确指出:
§10.3[...]在确定覆盖时不考虑访问控制(第11条)。
有点哲学背景:
进一步说明这是STL为iostreams
所做的事情:Non-Virtual Interface的定义,即所有公共函数(除了析构函数)都是非虚拟的,所有虚函数都是protected
或private
。公共函数调用虚拟保护或私有功能。这为整个层次结构提供了一个非常明确的切入点。
答案 1 :(得分:1)
确实如此,但您没有直接致电~Derived()
。如果您要使用
Derived *p = new Derived();
delete p;
然后你就会收到错误。但是当您通过多态性间接访问~Derived()
时(例如通过调用~Base()
),则访问说明符private
不适用。
虚函数的访问规则(Clause [class.access])由其声明确定,不受稍后覆盖它的函数规则的影响。 [实施例:
class B { public: virtual int f(); }; class D : public B { private: int f(); }; void f() { D d; B* pb = &d; D* pd = &d; pb->f(); // OK: B::f() is public, D::f() is invoked pd->f(); // error: D::f() is private }
- 结束示例]
再次在footnote 111 in [class.virtual]:
在确定覆盖时不考虑访问控制。
答案 2 :(得分:0)
您使用虚拟析构函数,因为您希望调用继承中的所有析构函数。这正是你得到的。私有不适用,因为你没有明确地调用析构函数。
如果您的析构函数不是虚拟的,那么只会调用<?php
class Login_model extends CI_Model
{
function login($username, $password)
{
$this->db->select('id, username, password');
$this->db->from('login');
$this->db->where('username', $username);
$this->db->where('password', $password);
$this->db->limit(1);
$query = $this->db->get();
if($query->num_row()==1)
{
return $query->result();
}
else
{
return false;
}
}
}
?>
。通常,当你有多态时,这不是你想要的。
答案 3 :(得分:0)
你可以通过指向B
的指针来调用析构函数,因为它已经在那里公开了。它是指针的静态类型,在这种情况下用于确定访问。
保持一致虚函数的访问规则(Clause [class.access])是 由其声明确定,不受a规则的影响 稍后覆盖它的函数。 [实施例:
class B { public: virtual int f(); }; class D : public B { private: int f(); }; void f() { D d; B* pb = &d; D* pd = &d; pb->f(); // OK: B::f() is public, D::f() is invoked pd->f(); // error: D::f() is private }
- 结束示例]
答案 4 :(得分:0)
您可以通过基类指针删除派生类。在虚拟析构函数的帮助下,您可以在派生类中启动删除。因为该类可以访问其私有成员,所以它会调用私有析构函数。之后,基类调用公共析构函数。
请注意,您调用删除而不是直接调用de destructor Derived :: ~Derived()!