析构函数

php的构造函数和析构函数

安稳与你 提交于 2019-12-07 07:36:29
PHP5可以在类中使用__construct()定义一个构造函数,具有构造函数的类,会在每次对象创建的时候调用该函数,因此常用来在对象创建的时候进行一些初始化工作。 class Car { function __construct () { print "构造函数被调用\n" ; } } $car = new Car(); // 实例化的时候 会自动调用构造函数__construct ,这里会输出一个字符串 在子类中如果定义了__construct则不会调用父类的__construct,如果需要同时调用父类的构造函数,需要使用parent::__construct()显式的调用。 class Car { function __construct () { print "父类构造函数被调用\n" ; } } class Truck extends Car { function __construct () { print "子类构造函数被调用\n" ; parent ::__construct(); } } $car = new Truck(); 同样,PHP5支持析构函数,使用__destruct()进行定义, 析构函数指的是当某个对象的所有引用被删除,或者对象被显式的销毁时会执行的函数。 class Car { function __construct () { print

面向对象的编程——构造函数和析构函数(1)

杀马特。学长 韩版系。学妹 提交于 2019-12-07 07:34:57
面向对象的编程——构造函数和析构函数(1) 构造函数与类同名我们以此来标识构造函数为了声明一个缺省的构造函数,构造函数上惟一的语法限制是它不能指定返回类型甚至void 也不行,C++语言对于一个类可以声明多少个构造函数没有限制,只要每个构造函数的参数表是惟一的即可。 析构函数是一个特殊的由用户定义的成员函数当该类的对象离开了它的域或者delete表达式应用到一个该类的对象的指针上时析构函数会自动被调用,析构函数的名字是在类名前加上波浪线(~),它不返回任何值,也没有任何参数,因为它不能指定任何参数。所以它也不能被重载。尽管我们可以为一个类定义多个构造函数但是我们只能提供一个析构函数,它将被应用在类的所有对象上。 #include <iostream> #include <string> #include <vector> using namespace std; class B { private: int data; public: B() { cout<<"default constructor"<<endl; } ~B() { cout<<"destructed"<<endl; } B(int i):data(i) { cout<<"constructed by parameter"<<data<<endl; } } ; B Play(B b) { return b; }

c++ 析构函数为什么要加virtual

一世执手 提交于 2019-12-07 07:34:07
这是因为当用基类引用派生类的时候,如果此时对基类进行delete操作,对于没有虚函数析构函数,那么只会调用基类的析构函数,而对派生类的析构函数不会进行析构 相关文章转载:http://www.cnblogs.com/lixiaohui-ambition/archive/2012/07/13/2589716.html 来源: CSDN 作者: gonaYet 链接: https://blog.csdn.net/qq_16097611/article/details/52053824

C++继承关于析构函数的问题

不打扰是莪最后的温柔 提交于 2019-12-07 07:33:37
析构函数的问题 关于C++中析构函数的作用,不再详述。 在c++继承中,也知道要把父类的析构函数用 virtual 修饰 关于析构函数的基本使用方法,也是很简单。 但是!最近在工作中,遇到了一个关于析构函数很奇怪的问题!导致查了半天的Bug,才发现是少声明了一个析构函数。 首先,存在Bug的代码,大体如下: // Base.h # define USE_EXPROT_ __attribut((visibility("default")) class USE_EXPROT_ Base { public : Base ( int id, int * p) : m_id (id) , m_p (p) {} public : int m_id; int * m_p; } // Child.h #include "Base.h" class Child : public Base { public : Child ( int id, int * p) : Base (id, p) {} virtual ~Child() {} } 上述代码编译中,没有报错。但是在运行中,有一处关于“Base*”的指针,虽然做了非NULL判断,但使用时总会出错(野指针)。 结果查了半天的Bug,最终如下修改解决了。 // Base.h # define USE_EXPROT_ __attribut(

析构函数写成virtual的好处

牧云@^-^@ 提交于 2019-12-07 07:32:55
相信学习c++的很多同志都听过这样的建议:最好将类的析构函数写成虚函数,如下: class B { public: B() { printf("B()\n"); } virtual ~B() { printf("~B()\n"); } private: int m_b; }; 这么写到底有什么好处呢? 我们通过示例给大家解释,示例1,析构函数为普通函数 //示例1 class B { public: B() { printf("B()\n"); } ~B() { printf("~B()\n"); } private: int m_b; }; class D : public B { public: D() { printf("D()\n"); } ~D() { printf("~D()\n"); } private: int m_d; }; int main() { B* pB = new D(); delete pB; return 0; } 运行结果如下(先不要看结果自己思考一下看看结果和你思考的是否相同): 图1 我们再看示例2,析构函数为虚函数 //示例2 class B { public: B() { printf("B()\n"); } virtual ~B() { printf("~B()\n"); } private: int m_b; }; class D :

C++将析构函数为啥需要定义成virtual

大憨熊 提交于 2019-12-07 07:32:39
一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,如题目中的A* d = new B();(假定A是基类,B是从A继承而来的派生类),那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常; 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再调用其基类的构造函数; 题目给出的代码是可以编译的,但会出现运行时错误。错误出现在delete d;这一句。为讨论方便,我们不妨将A类和B类改写如下: class A { public: int a; ~A() { cout << “A::~A” << endl; } }; class B : public A { public: int b; virtual ~B() { cout << “B::~B” << endl; } }; 那么A* d = new B();这一句的左边所产生B的对象的内存结构如下: 而A对象的内存结构如下: 可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。 如果将A类的析构函数设为虚的,那么A类对象的内存结构将为: B类对象的内存结构为: 此时通过A* d =

析构函数与virtual

别来无恙 提交于 2019-12-07 07:32:24
作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是virtual的。因为定义了虚函数则隐含着:这个类会被继承,并且会通过基类的指针指向子类对象,从而得到多态性。这个类可能会被继承,并且会通过基类的指针指向子类对象”,因此基类的析构函数是否为虚将决定子类的对象是否被析构。 #include <iostream.h> struct A { virtual ~A() {cout<<"~A()\n";} }; struct B: public A { ~B() {cout<<"~B()\n";} }; void main() { A* p = new B; delete p; } 如果 A 的析构函数不是virtual的,那么此时就不是先调用B的析构函数再调用A的析构函数。 输出为: ~A(); 如果 A 的析构函数为virtual,则先~B(),再~A(),输出为: ~B(); ~A(); 类如果会被派生的话,析构函数一般都应该定义为virtual的,主要不是防止内存泄露,而是为了正确的析构。如果是个封闭类(即不再被派生),就不要定义为virtual的。虚函数毕竟耗费较大的。 不用virtual 的几种情况: 作为非公有基类。仅作为 private base class 使用的 class 不需要使用虚拟析构函数。 不作为接口使用的基类。

为什么析构函数要声明成virtual

不羁的心 提交于 2019-12-07 07:30:06
(zz)为什么析构函数要声明成virtual 2011-03-08 15:43:00 | 分类: reproduct | 字号 订阅 为什么析构函数要声明成virtual呢? 因为,如果 delete 一个基类的指针时, 如果它指向的是一个子类的对象,那么析构函数不为虚就会导致无法调用子类析构函数,从而导致资源泄露。 当然,另一种做法是将基类析构函数设为 protected. 如果一个类要被使用成多态(polymorphic)的,那么这个virtual是必须的。比如: #include <iostream> class Animal { char* ap; public: Animal() { ap = new char; std::cout << "Animal ctor" << std::endl; } virtual void foo() { std::cout << "Animal::foo" << std::endl; } virtual ~Animal() { std::cout << "Animal dtor" << std::endl; delete ap; } }; class Dog : public Animal { char* dp; public: Dog() { dp = new char; std::cout << "Dog ctor" << std:

C++中基类的析构函数为什么要用virtual虚析构函数

倾然丶 夕夏残阳落幕 提交于 2019-12-07 07:29:33
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定。 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定、虚函数、多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。所以,为了防止这种情况的发生,C++中基类的析构函数应采用virtual虚析构函数。 示例代码讲解 现有Base基类,其析构函数为非虚析构函数。Derived1和Derived2为Base的派生类,这两个派生类中均有以string* 指向存储其name的地址空间,name对象是通过new创建在堆上的对象,因此在析构时,需要显式调用delete删除指针归还内存,否则就会造成内存泄漏。 class Base { public: ~Base() { cout << "~Base()" << endl; } }; class Derived1 : public Base { public: Derived1():name_(new string("NULL")) {} Derived1(const

Effective C++读书笔记之条款07:为多态基类声明virtual析构函数。

女生的网名这么多〃 提交于 2019-12-07 07:27:08
条款7:为多态基类声明virtual析构函数。 1、在创建有层次的类时,往往要把基类的析构函数声明为虚函数。 这是因为在使用这些类时,往往是通过基类指针或者引用使用的(类的实例在堆上),如果是析构对象时,通过delete +指针,这时如果析构函数不是虚函数,将不会调用当前指针指向对象的析构函数。这是多态的原理。 实例如下: https://blog.csdn.net/Struggling_Jeff/article/details/101381661 2、此外,要实现多态的函数,在基类也要声明为虚函数。 当一个类不用做基类时,如果把其析构函数声明为虚函数是个馊主意。因为虚析构是通过虚函数表调用的,在调用虚函数时多一步指针操作;除此之外,其对象占用的内存空间也会多一个虚函指针。 我们还容易犯这样的错误: 从标准库中的某个类中继承一个,用作自己的使用。但是,标准库中的很多类是不含virtual函数的!比如,string类,STL的容器类等等。 class MyString : public string { public : MyString ( string str , int i ) : s ( str ) , length ( i ) { } ~ MyString ( ) { cout << "MyString 析构函数" << endl ; } private : string