• C++ 语言学习 day02 (linux ) delete 函数 面对对象的类,构造函数,析构函数


    一、new的使用
        格式1: 指针名 = new 类型;
        格式1: 指针名 = new 类型(初始化值 );
        格式1: 指针名 = new 类型[元素个数];


       2.释放内存
          格式1:delete 指针名
          格式2: delete[] 指针名    只正对于new数组的情况 



      
      3.new malloc的区别(面试题)
        第一点:new是c++的,malloc是c的。
        第二点:new是运算符  ,malloc是函数,new要快于malloc
        第三点:malloc申请失败返回NULL,new申请失败返回异常;
        第四点: new和malloc都是在堆区申请的内存
        第五点:new是创建对象,创建的对象不需要强转,malloc需要 
        第六点: new的申请需要delete释放,malloc的申请需要free


       4. 注意: new 和delete是运算符  不是函数。


    代码:

    1. #include
    2. using namespace std;
    3. struct student
    4. {
    5. int age;
    6. };
    7. int main()
    8. {
    9. char* pc = new char(0);
    10. int * pi = new int;
    11. double * pd = new double[10];
    12. struct student* ps = new struct student;
    13. delete pc;
    14. delete pi;
    15. delete[] pd;
    16. delete ps;
    17. }

    二、类型转换
         c语言类型转换  (类型)变量名
         c++四种
               第一种: const_cast     把const类型变量转换成非const类型变量
               格   式:const_cast<类型> (变量名)
               练   习: 定义const指针变量,转换成非const,然后修改值后打印出来
                注意: 尖括号不可以省略 小括号不要省略
                           const_case 的尖括号中必须是指针或者引用类型



             第二种:dynamic_cast  
                 作用: 用于多态中类型的转换。(暂时不讲)



             第三种:static_cast
             作用:用于基本数据类型转换,也可以用于不同类对象的转换(父子类)
             格式: static_cast<类型>(变量)
                     double 转换成int
             特点:不会进行安全检查。



           第四种:reinterpret_cast 
             作用: 属于底层的强制类型转换,进行二进制的数据拷贝。
             使用: reinterpret_cast <类型>(变量名)


    代码:

    1. #include <iostream>
    2. int main()
    3. {
    4. //第一种数据类型转化
    5. int z = 10;
    6. const int* y = &z ;
    7. int* x = const_cast<int*> (y);
    8. cout << (*x) <<endl;
    9. //第二种数据类型转化
    10. double db = 123.8456;
    11. int idb = static_cast<int>(db);
    12. idb++;
    13. cout << idb <<endl;
    14. }


    三、面向对象
          1.面向对象编程(oop)
          主要是为了隔离数据,保护内部数据不被随意修改,同时限定变量的使用区域



          
          2.类定义
             定义一个类,有属性(成员变量),有行为(成员函数)。
            格式: class  类名
                       {
             修饰符:
                             定义变量;
                             定义函数;
                       };



          3.c++中结构体和类的区别
            第一个:在结构体中,默认为共有属性,而在类中是私有属性。



          4.成员修饰符
            共有属性: public:   可以在类内使用(类内函数中),可以在类外使用,可以在子类中使用。
            私有属性: private      只可以用于当前类内使用,类外和子类没法使用
            保护属性: protected:当前类内使用,子类使用。



         5.定义对象:类名 对象名;
                            对象名.成员变量;
                            对象名.成员函数();
                            对象指针 = new 类名称;  使用成员变量是需要用->  
                            对象指针->成员变量
                            对象指针->成员函数();  



         6.声明和实现分离
           原因:类什么和实现分离时为了隐藏实现部分。
                     实现接口化编程;
           格式:
                     定义类: class student {public: void show(); };
                     类外实现: void student::show(){cout <



       
          7.成员变量的set和get方法(私有)
             get是获取成员变量的值
             set是设置成员变量的值。


    代码:

    1. #include <iostream>
    2. using namespace std;
    3. class person
    4. {
    5. public:
    6. int age ;
    7. char* name;
    8. void show()//类内定义
    9. {
    10. cout << age <<endl;
    11. }
    12. void display(); //类内声明
    13. int getMoney()
    14. {
    15. return money;
    16. }
    17. void setMoney(int a)
    18. {
    19. age = a;
    20. }
    21. private:
    22. int money;
    23. };
    24. //类外实现。
    25. void person::display()
    26. {
    27. cout << money<<endl;
    28. }
    29. class student
    30. {
    31. private:
    32. int age = 10;
    33. public:
    34. char* name= "abc";
    35. void show();
    36. };
    37. class mynull{};//大小是1
    38. void student::show()
    39. {
    40. cout << age <<endl;
    41. }
    42. int main()
    43. {
    44. person danny;
    45. danny.age = 12;
    46. student huaqing;
    47. // cout << huaqing.name <<huaqing.age << endl;
    48. huaqing.show();
    49. cout << sizeof(mynull)<<endl;
    50. //new的方式创建对象
    51. student * pstu = new student;
    52. pstu->name;
    53. danny.setMoney(100000000);
    54. cout << danny.getMoney()<<endl;
    55. return 0;
    56. }


    四、构造和析构
           1构造函数:用来构造对象,每个对象创建时都会调用构造函数。
                           如果没有手动写构造,编译器会自动添加一个。
                           构造用来做初始化处理,变量的赋值,申请内存。



           2格      式: 类名(参数){ 内容}
           3注      意:构造函数的函数名是类名相同
                           构造函数没有返回值
                           构造函数有参合无参构成了重载
                           默认的构造函数,没有参数的函数版本 student(){ }
                           只要手动添加了构造,默认的构造就会消失。
                           只要手动添加的构造,都必须要有无参构造。(养成好习惯)



      
           4构造调用:构造函数不需要主动调用,当定义对象时会自动调用
                          对于有参构造,在定义对象时需要加小括号和参数,例如 stduent danny(10);
                         对于无参构造,直接类名+对象名构建对象,不需要加括号 例如 student danny;
                          如果某一个对象当做函数的参数,为了防止内存拷贝,需要使用引用。



            
          5.析构函数
             作用:在对象释放时内核自动调用析构函数
                       用来释放内存空间,用来关闭句柄等善后操作
             格式:~类名(){}
             注意:析构函数的名称是在类名前加~
                       析构函数不可以主动调用
                       析构函数没有参数,不可以有参数。
                       如果没有手动添加析构,编译器会自动添加析构函数。
             案例:
                class student    {
                    private:      int age;
                    public:    student(int a);
                                    student();
                                   ~student(){};
                 void setAge(int a)    {       age = a;    }
                 int getAge()    {        return age;    }
             };



       6. 拷贝构造
             拷贝构造:他是一种特殊的构造 (没有返回值,函数名是类名),特殊在参数是另外一个对象。
            格式: 类名(类名& 对象名){xxxx}
            调用: student dannyzai(danny);
                       student dannyzai = danny;  拷贝构造
                       fun(student abc){}  //避免拷贝构造 加引用


    代码:

    1. // 写一个代码:定义一个point类,
    2. // 有x和y坐标(int*),定义构造和拷贝构造,
    3. // 定义析构,在main函数中定义对象。(出现什么错误)
    4. #include <iostream>
    5. #include <cstring>
    6. using namespace std;
    7. class point{
    8. private:
    9. int* x;
    10. int* y;
    11. public:
    12. void setX(int a)
    13. {
    14. *x = a;
    15. }
    16. point(){ //无参构造
    17. x = new int(0);
    18. y = new int(0);
    19. }
    20. point(int a,int b){//有参构造
    21. //x = a;
    22. x = new int(a);
    23. y = new int(b);
    24. }
    25. point(int* a,int* b)//有参构造
    26. {
    27. //错误 x= a;y= b
    28. x = new int (*a);
    29. y = new int(*b);
    30. }
    31. point(point &a);//拷贝构造
    32. }
    33. point::point(point& a){
    34. /* x = a.x;
    35. y = a.y;*/
    36. if(x != NULL)
    37. {
    38. delete x;
    39. }
    40. if(y!= NULL)
    41. {
    42. delete y;
    43. }
    44. //
    45. if(this != &a)//防止引用自己
    46. {
    47. x = new int(*a.x);
    48. y = new int(*a.y);
    49. }
    50. cout << "abc"<<endl;
    51. }
    52. int main(int argc ,char* argv[])
    53. {
    54. point p1; //p1.x p1.y
    55. point p2 = p2; //p2.x = p1.x p2.y = p1.y 错误 doulbe free 两次释放
    56. point p3(10,20);
    57. int * pa = new int(10);
    58. point p4(pa,pa);
    59. delete pa;
    60. p4.setX(10);
    61. return 0;
    62. }



       7.拷贝方式:
         浅拷贝:浅拷贝只是拷贝了指针指向,不申请内存空间,存在多次释放相同内存的危险,需要避免使用。
         注意:如果没有手动写拷贝构造,编译器会自动添加默认的浅拷贝构造函数。
                  在拷贝构造函数中 要防止自拷贝 if(this != &other)
                  在拷贝构造中,如果指针不为空,需要先释放内存再进行申请
          深拷贝:深拷贝拷贝的是另一个对象的内容,不拷贝地址,新的对象有自己单独的内存空间,不会进行double free的情况。


    8.单列模式:

    何为单列模式  ; 不管实例化你创建多少的对象,我只给你们返回的总是哪一个

    1. 单例模式第一版:
    2. public class Singleton {
    3. private Singleton() {} //私有构造函数
    4. private static Singleton instance = null; //单例对象
    5. //静态工厂方法
    6. public static Singleton getInstance() {
    7. if (instance == null) {
    8. instance = new Singleton();
    9. }
    10. return instance;
    11. }
    12. }

    为什么这样写呢?我们来解释几个关键点:

    1.要想让一个类只能构建一个对象,自然不能让它随便去做new操作,因此Signleton的构造方法是私有的。

    2.instance是Singleton类的静态成员,也是我们的单例对象。它的初始值可以写成Null,也可以写成new Singleton()。至于其中的区别后来会做解释。

    3.getInstance是获取单例对象的方法。

    如果单例初始值是null,还未构建,则构建单例对象并返回。这个写法属于单例模式当中的懒汉模式。

    如果单例对象一开始就被new Singleton()主动构建,则不再需要判空操作,这种写法属于饿汉模式。

    这两个名字很形象:饿汉主动找食物吃,懒汉躺在地上等着人喂。但是上边单列不是线程安全的单列!

  • 相关阅读:
    【单独介绍主从同步的原理】SYNC和PSYNC的对比、优缺点_Redis08
    基于内容的推荐系统算法
    electron录制工具-系统托盘
    【C#】复杂Json的反序列
    【常见索引使用】⭐️Mysql中索引的类型以及使用方式和失效场景
    NPM 与 XUI 共存!Nginx Proxy Manager 搭配 X-UI 实现 Vless+WS+TLS 教程!
    软考-信息安全工程师-1
    IPV4和IPV6是什么?
    洛谷-线段覆盖-(区间排序问题总结)
    水果FL Studio/Cubase/Studio one音乐宿主软件对比
  • 原文地址:https://blog.csdn.net/she666666/article/details/126492098