析构函数

C++之保护和私有构造函数与析构函数

只谈情不闲聊 提交于 2020-02-28 19:57:43
一、构造函数 1、保护 构造函数定义为protected后,就意味着你不能在类的外部构造对象了,而只能在外部构造该类的子类的对象,比如: class Base { protected: Base() {} ... }; class Derived : public Base { public: Derived() {} ... }; Base b; //error Derived d; //ok 2、私有 构造函数定义为private后,意味着不仅仅不能在类的外部构造对象了,而且也不能在外部构造该类的子类的对象了,只能通过类的static静态函数来访问类的内部定义的对象,单件singleton模式就是私有构造函数的典型实例: class CLog { private: CLog() {}; public: ~CLog() {}; public: static CLog* GetInstance() { if (NULL == m_sopLogInstance) { CLock oInstanceLock; oInstanceLock.Lock(); if (NULL == m_sopLogInstance) { m_sopLogInstance = new CLog(); } oInstanceLock.Unlock(); } return m_sopLogInstance; }

C++类的六个特殊成员函数

我们两清 提交于 2020-02-28 00:15:25
1.设置六个函数的参数,先让函数运行起来 // // Created by liuhao on 20-1-1. // #include <iostream> //using namespace std; class Stu { private: std::string name = "无名氏 "; int age = 0; int *d = nullptr; public: Stu() { std::cout << name << age << " 执行了无参构造函数!" << std::endl; }; Stu(int a) { std::cout << name << age << " 执行了有参构造函数!" << std::endl; }; Stu(const Stu &s) { std::cout << name << age << " 执行了拷贝构造函数!" << std::endl; }; Stu &operator=(const Stu &s) { std::cout << name << age << " 执行了拷贝赋值运算符函数!" << std::endl; }; Stu(Stu &&s) { std::cout << name << age << " 执行了移动构造函数!" << std::endl; }; Stu &operator=(Stu &&s) {

子类构造、析构时调用父类的构造、析构函数顺序

不羁的心 提交于 2020-02-27 07:03:31
析构函数调用的次序是 先派生类的析构后基类的析构 ,也就是说在基类的的析构调用的时候,派生类的信息已经全部销毁了。 而 定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数;析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数。 原因: 派生类构造函数中的某些初始化可能是基于基类的,所以规定构造在类层次的 最根处 开始,而在 每一层,首先调用基类构造函数,然后调用成员( 此处的成员只指各种类对象如QString a,不含基本类型变量如int n、指针变量如QString *a )对象构造函数 ( 因为C++的成员变量是不会自动初始化的,只能使用初始化列表初始化(调用成员的构造函数,如果不在初始化列表中显式调用的话,则会隐式调用成员变量的默认构造函数,通过汇编可以发现)或在本层构造函数内初始化) 参考:http://www.cnblogs.com/lidabo/p/3790606.html )。 如果没有显式调用基类的构造函数,会自动调用基类的无参构造函数。而如果基类只有带参数的构造函数,则会报错。不一定要显式的无参构造函数,可以显式调用基类带参数的构造函数。 #include<iostream> using namespace std; class Base{ public: Base(int c){cout<< "基类带参构造函数" << c << endl

构造函数不可虚,析构可以虚

痴心易碎 提交于 2020-02-27 04:41:01
一.什么是虚函数: 可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时, 基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数, 而不是基类中定义的成员函数(只要派生类改写了该成员函数)。 若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都 会调用基类中定义的那个函数。 例 class A { virtual void AAA() { cout<<"这是基类的!"; } }; class a:A { void AAA() { cout<<"这是派生类a!"; } }; 然后你生成a的实例,调用AAA()方法时,程序调用的是a中的AAA,而不是A中的AAA 如果你不定义virtual,在生成a的实例后调用的是基类的AAA() 二.构造函数不可定义为虚函数: 1,从存储空间角度 虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。 2,从使用角度 虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。

构造函数不可虚,析构可以虚

久未见 提交于 2020-02-27 04:34:05
一.什么是虚函数: 可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时, 基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数, 而不是基类中定义的成员函数(只要派生类改写了该成员函数)。 若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都 会调用基类中定义的那个函数。 例 class A { virtual void AAA() { cout<<"这是基类的!"; } }; class a:A { void AAA() { cout<<"这是派生类a!"; } }; 然后你生成a的实例,调用AAA()方法时,程序调用的是a中的AAA,而不是A中的AAA 如果你不定义virtual,在生成a的实例后调用的是基类的AAA() 二.构造函数不可定义为虚函数: 1,从存储空间角度 虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。 2,从使用角度 虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。

构造函数与析构函数

爷,独闯天下 提交于 2020-02-27 04:02:19
构造函数 构造函数是一种特殊的成员函数,它主要用于为对象分配存储空间,对数据成员进行初始化。每个类都有构造函数,即使没有声明它,编译器也会自动提供一个默认的构造函数。使用构造函数时需要注意以下几个问题 构造函数名与类名相同 构造函数没有返回类型 构造函数的主要作用是完成对类的对象初始化 创建类的对象时(用new关键字),系统自动调用构造函数,即必须使用操作符new来调用一个构造函数 构造函数可以重载 利用“:this()”和“:base()”,构造函数可以调用其他构造函数 构造函数可以标记为public、private、protected、internal或protected internal 静态构造函数用static修饰,既没有访问修饰符,也没有参数 析构函数 析构函数是当销毁一个类的时候调用的函数,它用来释放创建类所占有的资源。析构函数具有以下几个特点: 析构函数的名字和类名相同,只是前面需要加一个“~”符号 不能在结构中定义析构函数,只能对类使用析构函数 一个类只能有一个析构函数 析构函数无法继承或重载 程序员无法调用析构函数,它是被自动调用的 析构函数既没有修饰符,也没有参数 程序员无法控制何时调用析构函数,因为这是由垃圾回收器决定的。 来源: https://www.cnblogs.com/ahao214/p/5785863.html

构造函数为什么不能为虚函数 & 基类的析构函数为什么要为虚函数

亡梦爱人 提交于 2020-02-27 03:24:15
一、构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的。问题出来了,假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。 2. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到相应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。虚函数的作用在于通过父类的指针或者引用来调用它的时候可以变成调用子类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。 3. 构造函数不须要是虚函数,也不同意是虚函数,由于创建一个对象时我们总是要明白指定对象的类型,虽然我们可能通过实验室的基类的指针或引用去訪问它但析构却不一定,我们往往通过基类的指针来销毁对象。这时候假设析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。 4. 从实现上看,vbtl在构造函数调用后才建立,因而构造函数不可能成为虚函数从实际含义上看,在调用构造函数时还不能确定对象的真实类型(由于子类会调父类的构造函数);并且构造函数的作用是提供初始化,在对象生命期仅仅运行一次

c++进阶八(派生类的析构函数)

心不动则不痛 提交于 2020-02-27 02:34:55
1,派生类对象被删除时析构函数的执行顺序 当对象被删除时,派生类的析构函数被执行, 先执行派生类的析构函数,再类的对象成员的析构函数,最后执行基类的析构函数 与构造函数的执行顺序相反 具体执行顺序: 1,先执行派生类的析构函数 2,执行类初始化表上的对象成员的析构函数 3,执行基类的析构函数 2,实例 通过运行下面实例来理解上面的过程 # include <iostream> using namespace std ; //类A的定义 class A { private : int x ; public : A ( int xp = 0 ) { x = xp ; cout << "A的构造函数被执行" << endl ; } ~ A ( ) { cout << "A类析构函数被执行" << endl ; } } ; class B { public : B ( ) { cout << "B的构造函数被执行" << endl ; } ~ B ( ) { cout << "B类析构函数被执行" << endl ; } } ; //创建C派生类 继承 A class C : public A { private : int y ; B b ; public : C ( int xp , int yp ) : A ( xp ) , b ( ) { y = yp ; cout <<

C++笔记(3):一些C++的基础知识点

99封情书 提交于 2020-02-26 23:05:08
前言: 找工作需要,最近看了下一些C++的基本概念,为范磊的 《零起点学通C++》,以下是一些笔记。 内容:   delete p;只是删除指针p指向内存区,并不是删除指针p,所以p还是可以用的。删除空指针所指向内存是可以的。   堆中的变量和对象时匿名的,没有名称,只能通过指针来访问。   在堆中创建对象时,在分配内存的同时会调用类的构造函数,在删除堆中对象时,会调用类的析构函数。   为了避免内存泄露,在删除一个指针后应该将其其值赋为0。   常量指针是指针指向的内存区域地址不能改变,但是该内存地址里保存的值是可以改变的,比如int a; int * const p = &a;   指向常量的指针表示指针指向的对象是不能被修改的,但是该指针可以被修改,即该指针可以指向另一块目标内存地址。比如const int a = 0; const int *p = &a; 如果A是一个类,也可以为const A* p = new A;   而指向常量的常指针表示指针本身不能被修改,其指向的内存地址内容也不能被修改。比如const int a = 0; const int * const p = &a;   引用就是别名常量。   堆中的地址是用指针来操作的,用不到别名。   如果在main函数前面的其它函数的声明和定义是一起的,则表明这个函数是内联函数!因此当该函数较长时

C++类的六个特殊成员函数

有些话、适合烂在心里 提交于 2020-02-24 21:07:36
1.设置六个函数的参数,先让函数运行起来 // // Created by liuhao on 20-1-1. // //================================================================================= #include <iostream> //using namespace std; class Stu { private: std::string name = "无名氏 "; int age = 0; int *d = nullptr; public: Stu() { std::cout << name << age << " 执行了无参构造函数!" << std::endl; }; Stu(int a) { std::cout << name << age << " 执行了有参构造函数!" << std::endl; }; Stu(const Stu &s) { std::cout << name << age << " 执行了拷贝构造函数!" << std::endl; }; Stu &operator=(const Stu &s) { std::cout << name << age << " 执行了拷贝赋值运算符函数!" << std::endl; }; Stu(Stu &&s) {