• 【C++】类和对象的知识点


    目录

    一,初始化列表

    二,static静态成员

    三,友元

    3-1,友元函数

    3-2,友元类   

    四,内部类

    五,匿名对象


    一,初始化列表

    引入:

            在谈初始化列表前,我们先清楚的认识下构造函数。构造函数的定义是在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,这里要注意的是,造函数调用之前,对象中已经有了一个初始值。也就是说构造函数体中的语句只能将其称为赋初值,而不能将其称为对象中成员变量的初始化,因为初始化是在建立时给予初值,而构造函数体内可以多次赋值。        

            在类对象中,对其成员变量进行初始化的操作叫初始化列表,初始化列表是一种用于初始化成员变量的语法结构,它在类的构造函数中使用,用于初始化类的成员变量。总的来说,初始化列表就是类成员变量的初始化。

    定义:

            初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个 “成员变量” 后面跟一个放在括号中的初始值或表达式。

    class Date
    {
    public:
        Date(int year, int month, int day)
            //初始化列表,对成员变量进行初始化
            :_year(year)
            ,_month(month)
            ,_day(day)
        {
            //...这里进行赋值操作
        }
    private:
        int _year;
        int _month;
        int _day;
    };

    初始化列表需注意以下几个要点:

            1,每个成员变量在初始化列表中只能出现一次,因为初始化只能初始化一次。

            2,类中包含以下成员,必须放在初始化列表位置进行初始化,不能调用构造函数:               

                    (1)引用成员变量。因为引用必须初始化,且一旦初始化后就不能改变,构造函数                  等于赋值操作。

                    (2)const成员变量。const修饰的变量不能改变,与引用成员变量同理。

                    (3)自定义类型成员(且该类没有默认构造函数时)。自定义类型运用初始化列表,相当            于直接给自定义类型直接赋值。相当于从内置类型转换成自定义类型(后面会详细讲解)。

    class A
    {
    public:
        A(int a = 6, int b = 5) //自己定义构造函数,编译器不会自动产生默认构造函数
            :_a(a)
            , _b(b)
        { /* ....... */ }
    private:
        int _a;
        int _b;
    };
    class B
    {
    public:
        B(int a = 1, int b = 1)
            :_aobj(a) //相当于隐式类型的转换
            ,_ref(b)
            ,_n(10)
        { /* ....... */ }
    private:
        A _aobj;  // 没有默认构造函数
        int& _ref;  // 引用
        const int _n; // const
    };
    int main()
    {
        B a(5);
        return 0;
    }

            3,因为初始化列表相当于初始化,所以初始化列表在变量定义时就调用。

            4,成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。

    class Date
    {
    public:
        Date(int year = 2023, int month = 10, int day = 16)
            //在编译器调用时依次调用_year,_month,_day,按照声明顺序调用
            : _month(month)
            , _day(day)
            , _year(year)
        {   }
    private:
        int _year;
        int _month;
        int _day;
    };

           这方面也经常会让我们运用,请观看以下代码:

    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. A(int a)
    7. :_a1(a)
    8. , _a2(_a1)
    9. {}
    10. void Print() {
    11. cout << _a1 << " " << _a2 << endl;//输出1和随机值
    12. }
    13. private:
    14. int _a2;//先调用初始化列表中的_a2
    15. int _a1;//再调用初始化列表中的_a1
    16. };
    17. int main() {
    18. A aa(1);
    19. aa.Print();
    20. }

            其实理解起来也非常简单,初始化列表是给变量初始化,在变量声明时就要开始赋值,因此,初始化列表是按照变量声明的顺序进行的。

            下面,要说明的是在构造函数中不能只要初始化列表,不要函数体初始化,因为有些初始化或者检查工作,初始化列表也不能全部解决,如下:

    class Stack
    {
    private:
        Stack(int capacity = 5)
            : _capacity(capacity)
            , _top(-1)
        {
            //a初始化时要进行检查工作,在初始化列表中不能完成
            a = new int[capacity];
            if (a == nullptr) {
                perror("malloc fial");
                exit(-1);
            }
        }
    private:
        int* a;
        int _capacity;
        int _top;
    };

    总:通过以上学习可看出,初始化列表也不能解决全部问题,在后面的学习和深入探索中,初始化列表和构造函数实体往往是混合使用的。


    二,static静态成员

    概念:

            声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数。

    注意:

            1,静态成员也是类的成员,受public、protected、private访问限定符的限制。

            2,静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区,可用sizeof关键字进行查看。

    class Date1 //占12个字节
    {
        int _year;
        int _month;
        int _day;
        static int _a;
    };
    class Date2 //占16个字节
    {
        int _year;
        int _month;
        int _day;
        int _a;
    };

            3,静态成员变量必须在类外进行初始化和定义,定义时不添加static关键字,类中只是声明。因为静态成员没有存储在类中,存储在静态区中,不能对其进行类中的操作。

    class Date1
    {
    public:
        Date1(int year = 2023, int month = 10, int day = 16)
            : _year(year)
            , _month(month)
            , _day(day)
            //, _a(2)错误,因为静态成员变量没有存储在类中
        {     }
        int _year;
        int _month;
        int _day;
        static int _a;
    };
    int Date1::_a = 5;//对静态成员变量进行初始化

            4,类静态成员即可用类名::静态成员或者对象.静态成员来访问,但这两种方法访问的权限必须为公有。用类的成员函数也可间接访问,这种方法可间接的在类外访问私有权限的成员。

    1. #include
    2. using namespace std;
    3. class Date1
    4. {
    5. public:
    6. Date1(int year = 2023, int month = 10, int day = 16)
    7. : _year(year)
    8. , _month(month)
    9. , _day(day)
    10. { }
    11. int GetData() {
    12. return _a;
    13. }
    14. int _year;
    15. int _month;
    16. int _day;
    17. static int _a;
    18. };
    19. int Date1::_a = 5;
    20. int main()
    21. {
    22. Date1 d1;
    23. cout << d1._a << endl;//权限必须公有
    24. cout << Date1::_a << endl;//权限必须公有
    25. cout << d1.GetData() << endl;//即使权限私有也可访问
    26. return 0;
    27. }

            5,静态成员函数没有隐藏的this指针,不能访问任何非静态成员,但可以访问静态成员,因为访问类中非静态成员需要this指针来 “指引” ,而静态成员存储在静态区中,可以随时访问。

    class Date1
    {
    public:
        Date1(int year = 2023, int month = 10, int day = 16)
            : _year(year)
            , _month(month)
            , _day(day)
        {       }
        static int GetData()
        {
            //return _year;//没有this指针,找不到此对象
            return _a;//_a为静态成员,不在类中,可以访问
        }
        int _year;
        int _month;
        int _day;
        static int _a;
    };

            这里要说明的是静态成员函数不可以调用非静态成员函数,但非静态成员函数可以调用类的静态成员函数。静态成员函数由于没有this指针,不能访问类中成员,静态成员函数跟静态成员变量一样,都存储在静态区中,所以可以任意访问。


    三,友元

           在C++中,友元是一个关键字,它用于允许一个类的成员函数访问另一个类的私有和保护成员。使用友元函数或友元类,可以访问一个类的私有和保护成员,就像它们是公共成员一样。其中友元共分为:友元函数友元类

    3-1,友元函数

           友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

    class Date
    {
        //友元函数的声明
        friend ostream& operator<<(ostream& _cout, const Date& d);
        friend istream& operator>>(istream& _cin, Date& d);
    public:
        Date(int year = 2023, int month = 10, int day = 16)
            : _year(year)
            , _month(month)
            , _day(day)
        {    }
    private:
        int _year;
        int _month;
        int _day;
    };
    //友元函数的定义
    ostream& operator<<(ostream& _cout, const Date& d)
    {
        _cout << d._year << "-" << d._month << "-" << d._day;//访问类中的私有成员变量
        return _cout;
    }
    istream& operator>>(istream& _cin, Date& d)
    {
        _cin >> d._year >> d._month >> d._day;//访问类中的私有成员变量
        return _cin;
    }

    这里要说明以下几点:

            1,友元函数可访问类的私有和保护成员,但不是类的成员函数。

            2,友元函数不能用const修饰。

            3,友元函数可以在类定义的任何地方声明,不受类访问限定符限制。

    3-2,友元类   

            在C++中,友元类是一种特殊的关系,它允许一个类访问另一个类的私有和保护成员。使用友元类,可以访问一个类的私有和保护成员,就像它们是公共成员一样。

            要声明一个类为另一个类的友元类,可以在类定义中加入friend关键字,并使用类名作为友元类的声明。

    class Time
    {
        // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
        friend class Date;  
        int _hour;
        int _minute;
        int _second;
    };
    class Date
    {
    public:
        void SetTimeOfDate(int hour, int minute, int second)
        {
            // 直接访问时间类私有的成员变量
            _t._hour = hour;
            _t._minute = minute;
            _t._second = second;
        }
    private:
        int _year;
        int _month;
        int _day;
        Time _t;
    };


    四,内部类

    概念:

            如果一个类定义在另一个类的内部,那么这个定义在内部的类就叫做内部类。内部类是一个独立的类, 它不属于外部类,更不能通过外部类的对象去访问内部类的成员,即外部类不是内部类的友元,但内部类是外部类的友元类,即内部类可以通过外部类的对象参数来访问外部类中的所有成员。

    注意:

            1,内部类可以直接访问外部类中的静态成员,不需要外部类的对象/类名。

            2,定义内部类时不能直接定义,需要外部类来限定域的作用空间。

    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. private:
    6. static int k;
    7. int h;
    8. public:
    9. class B // B天生就是A的友元
    10. {
    11. public:
    12. void fun(const A& a)
    13. {
    14. //这里要说明的是内部类可以直接访问外部类中的静态成员,不需要外部类的对象/类名
    15. cout << k << endl;//直接访问静态成员
    16. cout << a.h << endl;//访问A类中的私有成员
    17. }
    18. };
    19. };
    20. int A::k = 1;
    21. int main()
    22. {
    23. A::B b;//定义内部类对象b
    24. return 0;
    25. }

    五,匿名对象

    概念:在类中,我们可以对类进行不取名字的方式定义,这种定义对象的方式叫做匿名对象。其中,匿名对象的生命周期只有这一行,当这一行结束时将会自动调用析构函数。

            匿名对象在只需使用一次的场合下非常好用,这里我们先了解一下,后面的文章将会深入展开这一方面。使用如下:

    1. #include
    2. using namespace std;
    3. class A
    4. {
    5. public:
    6. A(int a = 0)
    7. :_a(a)
    8. { }
    9. ~A()
    10. {
    11. cout << "~A()" << endl;
    12. }
    13. int GetData() {
    14. return _a;
    15. }
    16. private:
    17. int _a;
    18. };;
    19. int main()
    20. {
    21. A();//建立匿名对象,这一行结束后将调用析构函数
    22. A().GetData();//使用匿名对象调用成员函数,结束后将自动调用析构函数
    23. return 0;
    24. }

    总:本章节只是初步学习类与对象中的知识点,具体的深入探索到了后面会详细讲解,这里我们只需先理解并会用即可。

  • 相关阅读:
    合宙昆仑镜LCD驱动测试
    redisson究极爽文-手把手带你实现redisson的发布订阅,消息队列,延迟队列(死信队列),(模仿)分布式线程池
    Google Pay最新版集成步骤
    leetcode 215.数组中第k大的元素
    ICASSP2023年SPGC多语言AD检测的论文总结
    印象深刻的bug汇总(持续更新)
    结束八天了,还是无法与她和解. --vulnhub 靶场
    GD32F10 串口通信
    毕业设计|基于stm32单片机的app视频遥控抽水灭火小车设计
    【Leetcode】14. 最长公共前缀
  • 原文地址:https://blog.csdn.net/m0_74246469/article/details/134449081