• <C++> 类(2):对象的种类 类之间的关系 重载操作符operator


    一.对象的种类

    1.全局对象:

    ①生命周期:程序结束

    ②执行顺序:return 0 → } → 析构

    2.栈区局部对象:

    ①生命周期:作用域结束

    ②执行顺序:return 0 → 析构 → }

    3.堆区的指针对象:

    ①生命周期:遇到delete结束

    注:new出来的对象没有delete就没有析构函数 哪怕是作用域结束了也没有

    4.临时对象:

    ①生命周期:仅限当前这一行

    ②代码说明:

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CPerson
     5 {
     6 public:
     7     CPerson QQ()
     8     {
     9         CPerson qq;
    10         return qq;
    11     }
    12 };
    13 
    14 int main()
    15 {
    16     CPerson kk;
    17     kk = kk.QQ();
    18 
    19     return 0;
    20 }

    其实到return pp的那一行 return完了就已经把qq删了 所以才会创建一个临时对象接着qq的值

    也就是说 下面主函数在第17行执行调用QQ函数的时候 会在这一行创建一个临时对象

    临时对象的产生是电脑做的 临时对象的构造函数执行的是电脑里面默认的

    用这个临时对象接着函数的返回值 然后把这个临时对象装在kk里面

    如果你不想让他创建临时对象的话 可以把函数返回值和参数改成CPerson&类型的

    返回值类型如果是CPerson 那么在外面就叫创建临时对象

    返回值类型如果是CPerson& 这就相当于只是把一个名字拿出来了

    总结:大部分对象都是在堆区new出来的 因为这样比较方便去控制他的生命周期

    5.为什么有了malloc和free还要有new和delete呢?(new还是用malloc去定义的)

    malloc和free是不调用构造函数和析构函数的 只是单纯的去申请空间和释放空间的

    但是!!!

    new:①分配空间 ②调用构造和初始化 ③返回空间地址

    delete:①调用析构 ②删除对象空间

    也就是说:new和delete都可以触发构造函数和析构函数

    6.杂乱补充:

    空类的大小:一个字节(后面还会对空类的内容进行补充)

    类是抽象的 不存在的 是有定义类的实体 也就是只有定义对象的时候 才会被分配空间

    ②成员变量和成员函数:

    成员变量是在创建对象的时候就存在的 普通的成员变量每个对象都有一份 静态成员变量是所有对象公用一份(这个在后面也会再写 具体有所补充)

    成员函数是在编译的时候就存在了 并且只有一份

    ③不同的地址取得的就是不同的变量 谁调用就用谁的地址 就把谁的地址传进去

    普通的成员函数 都会有一个隐藏的参数:CPerson* this(拿CPerson为例)

    每一个普通的成员参数都有一个隐藏的指针this 这个指针用来装调用对象的地址 用来区分不同对象的成员

    例如:

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CPerson
     5 {
     6 public:
     7     int a;
     8 public:
     9     CPerson(int b)
    10     {
    11         a = b;
    12     }
    13     void Show(/*CPerson* this*/)
    14     {
    15         cout << this << endl;
    16         cout << this -> a << endl;
    17     }
    18 };
    19 
    20 int main()
    21 {
    22     CPerson aa(100);
    23     cout << &aa << endl;
    24     aa.Show(/* &aa */);
    25 
    26     CPerson bb(200);
    27     cout << &bb << endl;
    28     bb.Show(/* &bb */);
    29     return 0;
    30 }

    二.类之间的关系

    类之间的关系分为两种:

    1.纵向关系:继承

    ①语法:class CSuperman : public CPerson{ ... };

    把父类中的所有成员拿过来

    横线处的访问修饰符可以替换 访问修饰符不同 继承过来也是有差别的

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CPerson
     5 {
     6 public:
     7     void ShowEat()
     8     {
     9         cout << "吃饭" << endl;
    10     }
    11 };
    12 
    13 class CSuperMan : public CPerson
    14 {
    15 public:
    16     void ShowFly()
    17     {
    18         cout << "我能飞" << endl;
    19     }
    20 };
    21 
    22 int main()
    23 {
    24     CSuperMan sm;
    25     sm.ShowEat();
    26     sm.ShowFly();
    27 
    28     return 0;
    29 }

    ②原有类:基类 父类

    新类:派生类 子类

    ③作用:提高复用性

    ④父类和子类中同名的成员变量和成员函数是通过作用域来区分的

    子类的大小=子类+父类

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CFather
     5 {
     6 public:
     7     int m_nMoney;
     8 public:
     9     CFather()
    10     {
    11         m_nMoney = 1000000;
    12     }
    13 };
    14 
    15 class CSon : public CFather
    16 {
    17 public:
    18     int m_nMoney;
    19 public:
    20     CSon()
    21     {
    22         m_nMoney = 100;
    23     }
    24 };
    25 
    26 int main()
    27 {
    28     CFather cf;
    29     CSon cs;
    30 
    31     cout << cs.m_nMoney << endl;
    32     cout << cs.CFather::m_nMoney << endl;
    33     cout << sizeof(cs) << endl; //输出 8
    34 
    35     return 0;
    36 }

    继承方式:影响的是继承过来的访问修饰符 即子类的访问修饰符

    public继承:public和protected没有变化 但是父类的private在子类中是不可访问的

    protected继承:public变成protected protected不变 private依然不可访问

    private继承:public和protected都变成private 所有内容不可访问

    特别注意:自己的类中不可定义自己的类对象 但是定义指针可以!!!

    ⑦继承关系的构造和析构函数的调用顺序:

    定义一个派生类对象:先执行父类构造 然后子类构造 然后子类析构 父类析构

    换句话说 构造函数是从父类到子类 析构是从子类到父类

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class CFather
     5 {
     6 public:
     7     CFather()
     8     {
     9         cout << "CFather" << endl; 
    10     }
    11     ~CFather()
    12     {
    13         cout << "~CFather" << endl; 
    14     }
    15 };
    16 
    17 class CSon : public CFather
    18 {
    19 public:
    20     CSon()
    21     {
    22         cout << "CSon" << endl; 
    23     }
    24     ~CSon()
    25     {
    26         cout << "~CSon" << endl; 
    27     }
    28 };
    29 
    30 int main()
    31 {
    32     CSon son;
    33 
    34     return 0;
    35 }

    注意:

    父类的构造函数是在子类的构造函数初始化列表中调用的 默认的调用是无参的

    如果父类中只有带参数 也需要在子类的构造函数初始化列表中调用带参数的

    2.横向关系:依赖<关联<聚合<组合

    ①组合:是部分与整体的关系

    它是你的一部分 缺少一部分就是不完整的

    直接要求:包含对象对被包含对象的拥有 以及 包含对象与被包含对象生命期的关系

    例如:笔记本电脑和笔记本电脑键盘 汽车和轮胎 人和手

    ②聚合:是一对多的关系

    暗含了一种所属关系以及生命期的关系(有无是不一定的) 被聚合对象还可以再被别的对象关联

    注意:是A中放了多个B 而不是A中放了B C D

    例如:班级有很多人 部门有很多职工

    ③关联:

    某个对象长期持有对另一对象的引用 可以随时解除关联或者进行关联

    关联是没有生命周期的 可以是相互的

    例如:朋友(人在出生的时候 可以在类里放一根指针 有就指向这个对象 没有就指空)

    ④依赖:

    某个对象的功能依赖另外一个对象 被依赖的对象只作为工具使用

    依赖是没有生命周期的 只是使用 不持有对它的引用

    例如:人依赖空气呼吸

    3.总结

    ①有生命周期的:组合和聚合

    ②没有生命周期的:关联和依赖

    三.重载操作符operator

    1.重载操作符有两种方法:

    在类内:调用的对象一定在左边

    在类外:需要有符号左边和符号右边(双目运算符)

    2.需要注意的地方:

    ①表达式都有结果 所以重载的符号需要有返回值 返回值是为了和其他符号结合

    ②在重载输入输出操作符的时候 输入一定要放& 否则是改变不了其中的内容的

    输出无所谓(这么说未免太不负责任) 但是为了养成良好的习惯 还是都加上比较好 也方便记忆嘛

    3.代码:

     1 #include<iostream>
     2 using namespace std; 
     3 
     4 class CNum
     5 {
     6 public:
     7     int m_num; 
     8 public:
     9     CNum(void)
    10     {
    11     }
    12 
    13     ~CNum(void)
    14     {
    15     }
    16 
    17     int operator=(int num)
    18     {    
    19         this -> m_num = num;
    20         return m_num;
    21     }
    22 
    23     int operator+(int num)
    24     {
    25         return this -> m_num + num;
    26     }
    27 
    28     int operator++()
    29     {
    30         m_num = m_num + 1;
    31         return m_num;
    32     }
    33 
    34     int operator++(int aaa)
    35     {
    36         aaa = m_num;
    37         m_num = m_num + 1;
    38         return aaa;
    39     }
    40 };
    41 
    42 int operator+(int num,CNum& cn)
    43 {
    44     return num + cn.m_num;
    45 }
    46 int operator+(CNum& cn1,CNum& cn2)
    47 {
    48     return cn1.m_num + cn2.m_num;
    49 }
    50 
    51 istream& operator>>(istream& is,CNum& cn)
    52 {
    53     cin >> cn.m_num;
    54     return is;
    55 }
    56 
    57 ostream& operator<<(ostream& os,CNum& cn)
    58 {
    59     cout << cn.m_num;
    60     return os;
    61 }
    62 
    63 int main()
    64 {
    65     CNum a;
    66     a = 100;
    67     cout << a.m_num << endl; //100
    68 
    69     CNum b;
    70     b = a = 200;
    71     cout << a.m_num << endl; //200
    72     cout << b.m_num << endl; //200
    73 
    74     CNum c;
    75     c = a + 100;
    76     cout << c.m_num << endl; //200+100=300
    77 
    78     CNum d;
    79     d = 100 + a;
    80     cout << d.m_num << endl; //100+200=300
    81 
    82     CNum e;
    83     e = a + b;
    84     cout << e.m_num << endl; //200+200=400
    85 
    86     cin >> a;
    87     cout << a << endl;
    88 
    89     return 0;
    90 }
  • 相关阅读:
    python全栈开发_day17_时间,系统模板和序列化
    python全栈开发_day15_函数回调和模块
    python全栈开发_day16_包
    pygame学习_part1_pygame写程序前的准备工作
    python全栈开发_day15_模块学习
    不确定性推理复习
    hibernate级联关系
    hibernate双向一对多关联关系
    实践:hibernate-one2many(单向)
    我的学习(修改完善)
  • 原文地址:https://www.cnblogs.com/Aaaaaalei0612/p/9156657.html
Copyright © 2020-2023  润新知