• C++学习笔记三(类和对象)


    一、示例

    二、封装

    1)访问权限:

    2)struct和class的区别

    3)成员属性私有化

    三、对象特性

    1)构造函数和析构函数

    2)构造函数的分类和调用

    3)构造函数的调用规则

    4)深拷贝与浅拷贝

    5)初始化列表

    6)静态成员

    7)this指针的用途

    8)空指针访问成员函数

    9)const修饰成员函数(常函数)

    10)友元

    四、运算符的重载

      1)重载加号+

      2)重载左移<<

      3)重载++运算符

      4)重载赋值运算符=

      5)重载关系运算符==

      6)重载函数调用运算符()----仿函数

    五、继承

      1)继承语法

      2)继承方式

      3)构造函数和析构函数的执行顺序

      4)继承同名成员处理方式

      5)继承同名静态成员处理方式

      6)多继承

      7)菱形继承与虚继承

    六、多态

      1)语法

      2)动态多态代码实例

      3)纯虚函数和抽象类

      4)虚析构和纯虚析构

    一、示例

    class Circle {
    public://访问权限
        double r;
        double GetArea()
        {
            return r * r * 3.14;
        }
    };
    int main()
    {
        Circle c1;
        c1.r = 10;
        cout << c1.GetArea() << endl;
        system("pause");
        return 0;
    }

    二、封装

    1)访问权限:

    ①public公共权限        成员类内可以访问,类外也可以访问。

    ②protected保护权限  成员类内可以访问,类外不可以访问,但是儿子可以访问。

    ③private私有权限      成员类内可以访问,类外不可以访问,儿子也不可以访问。

    2)struct和class的区别

    struct成员默认权限是公有public,class成员默认权限是私有private。

    3)成员属性私有化

    class Student {
    private:
        int age;
        string name;
        string num;
    
    public:
        int GetAge()
        {
            return this->age;
        }
        void SetAge(int age)
        {
            this->age = age;
        }
    };
    int main()
    {
        Student stu1;
        stu1.SetAge(21);
        cout << stu1.GetAge();
    
        system("pause");
        return 0;
    }

    三、对象特性

    1)构造函数和析构函数

    ①构造函数语法:类名(){};

    ②析构函数语法:~类名(){};

    2)构造函数的分类和调用

       分类:

    ①有参构造和无参构造

    ②拷贝构造函数:

    Student(const Student& stu)
        {
            //.......
        }

       调用:

    ①调用默认参数时不需要加(),不然,Student stu()会被认为是一个函数声明:

    Student stu;

    ②调用有参构造:

    Student stu1=Student(10);

    ③调用拷贝构造:

    Student stu2=Student(stu1);

    ④匿名对象:

    Student(10);//当前行执行结束,系统会立即回收掉匿名对象

    ⑤隐式转换法:

    Student stu1=10;//相当于Student stu1=Student(10)
    Student stu2=stu1;//相当于拷贝构造

    3)构造函数的调用规则:

    ①创建一个类,C++编译器会给每个类添加至少三个函数:默认构造,析构函数,拷贝构造。

    ②如果用户定义有参构造函数,那么编译器将不再提供无参构造函数,但是会提供默认拷贝构造函数。

    ③如果用户定义拷贝构造函数,那么C++将不会提供其他构造函数。

    4)深拷贝与浅拷贝

    浅拷贝:

    Student(const Student &stu)
    {
        age=stu.age;
    }

    深拷贝(重新再堆区创建一块内存保存数据):

    Student(const Student &stu)
    {
        age=new int(*stu.age);
    }

    总结:如果有属性是在堆区开辟的内存,就要自己构造拷贝函数,防止浅拷贝带来的问题。

     5)初始化列表

    Student(int a, string b, string c) :age(a),name(b),num(c)
        {
    
        }

    等价于:

    Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }

    6)静态成员

    ①定义:在成员前面加上static称为静态成员。

    ②调用静态成员(两种方法):

    通过对象访问:

    Person p;
    p.func();

    通过类名访问:

    Person::func();

    ③静态成员函数可以访问静态成员变量,但是不可以访问非静态成员变量,因为无法区分到底是哪个对象的变量。

     7)this指针的用途

    ①当形参和成员变量同名时,可以用this来区分;

    ②在类的非静态成员函数中返回对象本身,可以使用return *this。

    8)空指针访问成员函数

    class Student {
    private:
        int age;
        string name;
        string num;
    public:
        Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }
        void ShowAge()
        {
            if (this == NULL)
                return;
            cout << age << endl;
        }
        void ShowName()
        {
            cout << "hello world" << endl;
        }
    
    };
    int main()
    {
        Student* s = NULL;
        s->ShowAge();
        system("pause");
        return 0;
    }

    9)const修饰成员函数(常函数)

    ①常函数内不可以修改成员属性;

        成员属性声明时加关键字mutable后,就可以修改成员属性了。

    class Student {
    private:
        int age;
        mutable string name;
        string num;
    public:
        Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }
        void ShowName() const
        {
            this->name = "jack";
            cout << "hello world" << endl;
        }
    
    };

    ②常对象只能调用常函数

    class Student {
    private:
        int age;
        mutable string name;
        string num;
    public:
        Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }
        void ShowAge()
        {
            if (this == NULL)
                return;
            cout << age << endl;
        }
        void ShowName() const
        {
            this->name = "jack";
            cout << "hello world" << endl;
        }
    
    };
    int main()
    {
        const Student s;
        s.ShowName();
        system("pause");
        return 0;
    }

    10)友元

    ①友元的目的是为了让一个函数或者类访问另一个类中的私有成员。

        友元关键字为friend。

     ②友元的三种实现:

    全局函数做友元

    class Student {
        //全局函数可以访问当前类对象的私有成员
        friend void ShowInfor(Student s);
    private:
        int age;
        mutable string name;
        string num;
    public:
        Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }
    };
    
    //全局函数
    void ShowInfor(Student s)
    {
        cout << s.age << endl;
    }

    类做友元

    class Student {
        //另一个类可以访问当前类对象的私有成员
        friend class Teacher;
    
    private:
        int age;
        mutable string name;
        string num;
    public:
        Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }
    };
    class Teacher {
    private:
        string name;
        int age;
    public:
        void Visit(Student s)
        {
            cout << s.name << s.age << endl;
        }
    };

    成员函数做友元

    class Student {
        //Visit1可以访问当前类对象的私有成员,Visit2不能
        friend void Teacher::Visit1(Student s);
    
    private:
        int age;
        mutable string name;
        string num;
    public:
        Student(int age,string name,string num)
        {
            this->age = age;
            this->name = name;
            this->num = num;
        }
    };
    class Teacher {
    private:
        string name;
        int age;
    public:
        void Visit1(Student s)
        {
            cout << s.name << s.age << endl;
        }
    
        void Visit2(Student s)
        {
    
        }
    };

    四、运算符重载

    1)加号运算符重载

        ①通过成员函数重载加号

        

    class Person {
    public:
        int age;
        Person(int age)
        {
            this->age = age;
        }
        //通过成员函数
        Person operator+(Person &p)
        {
            Person p1 = Person(30);
            p1.age = this->age + p.age;
            return p1;
        }
    };

       ②通过全局函数重载加号

    class Person {
    public:
        int age;
        Person(int age)
        {
            this->age = age;
        }
        
    };
    
    //通过全局函数
    Person operator+(Person& p1, Person& p2)
    {
        Person p = Person(10);
        p.age = p1.age + p2.age;
        return p;
    }
    int main()
    {
        Person p1 = Person(10);
        Person p2 = Person(20);
        Person p3 = p1 + p2;
        cout << p3.age << endl;
    
        system("pause");
        return 0;
    }

     2)左移运算符

    只能通过全局函数重载左移运算符

    class Person {
    public:
        string name;
        int age;
        Person(string a,int b):name(a),age(b)
        {
    
        }
    };
    
    ostream &operator<<(ostream &cout, Person &p)
    {
        cout << p.name << endl << p.age;
        return cout;
    }
    
    
    int main()
    {
        Person p = Person("jack", 19);
        cout << p << endl;
        system("pause");
        return 0;
    }

     3)重载++运算符

    class Person {
        friend ostream &operator<<(ostream& cout, Person& p);
    private:
        string name;
        int age;
    public:
        Person(string a,int b):name(a),age(b)
        {
    
        }
        //前置++运算符
        Person& operator++()
        {
            this->age++;
            return *this;
        }
    
        //后置++运算符,int用于区分前置运算符
        Person operator++(int)
        {
            Person temp = *this;
            age++;
            return temp;
        }
    };
    
    ostream &operator<<(ostream &cout, Person &p)
    {
        cout << p.name << endl << p.age;
        return cout;
    }
    
    
    int main()
    {
        Person p = Person("jack", 19);
        cout << ++p << endl;
        system("pause");
        return 0;
    }

    4)赋值运算符

    class Person {
        friend ostream &operator<<(ostream& cout, Person& p);
    private:
    public:
        int* age;
        Person(int b)
        {
            age = new int(b);
        }
        ~Person()
        {
            if (age != NULL)
            {
                delete age;
                age = NULL;
            }
        }
        Person& operator==(Person p)
        {
            //先判断是否有属性在堆区,若有先释放干净,然后再深拷贝
            if (age != NULL)
            {
                delete age;
                age = NULL;
            }
            //深拷贝
            age = new int(*p.age);
    
            return *this;
        }
    };
    
    ostream &operator<<(ostream &cout, Person &p)
    {
        cout << p.age<<endl;
        return cout;
    }
    
    
    int main()
    {
        Person p1 = Person(19);
        Person p2 = Person(20);
        p2 = p1;
        cout << *p2.age << endl;
        system("pause");
        return 0;
    }

    5)关系运算符

    class Person {
    public:
        int age;
        Person(int b):age(b)
        {
            
        }
        bool operator==(Person p)
        {
            if (p.age == age)
    
                return true;
    
            else
    
                return false;
        }
    };
    
    
    int main()
    {
        Person p1 = Person(19);
        Person p2 = Person(20);
        bool f = p1 == p2;
        cout << f;
        system("pause");
        return 0;
    }

    6)重载函数调用运算符(),也称为仿函数

    class Person {
    public:
        int age;
        Person(int b):age(b)
        {
            
        }
        void operator()(string s)
        {
            cout << s << endl;
        }
    };
    int main()
    {
        Person p1 = Person(19);
        Person p2 = Person(20);
        p1("shidhapi");
        system("pause");
        return 0;
    }

     五、继承

    1)  继承语法:class   子类:  继承方式   父类

    2)继承方式(3种):①公共继承;②保护继承;③私有继承。

    3)构造函数和析构函数的执行顺序

    父类构造函数->子类构造函数->子类析构函数->父类析构函数

    4)继承同名成员处理方式

    ①同名成员属性处理方式

    #include <iostream>
    using namespace std;
    
    class Base {
        public:
            Base() {
                m_A = 100;
            }
            int m_A;
    };
    
    class Son : public Base {
        public:
            Son() {
                m_A = 200;
            }
            int m_A;
    };
    
    void test01() {
        Son s;
        cout << "Son 下 m_A = " << s.m_A << endl;
        //如果通过子类对象 访问到父类中的同名成员 需要加作用域
        cout << "Base 下 m_A = " << s.Base::m_A << endl;
    }
    int main() {
        test01();
        return 0;
    }

    ②同名成员函数处理方式

    #include <iostream>
    using namespace std;
    
    class Base {
        public:
            Base() {
                m_A = 100;
            }
    
            void func() {
                cout << "Base fun()调用" << endl;
            }
            void func(int a) {
                cout << "Base fun(int a)调用" << endl;
            }
            int m_A;
    };
    
    class Son : public Base {
        public:
            Son() {
                m_A = 200;
            }
            void func() {
                cout << "Son fun()调用" << endl;
    
            }
            int m_A;
    };
    
    void test01() {
        Son s;
        s.func();//直接调用 调用是子类中的同名成员
        //如何调用父类中同名成员函数?
        s.Base::func();
        s.Base::func(100);
    }
    int main() {
        test01();
        return 0;
    }

    5)继承同名静态成员处理方式

    ①同名静态成员属性

    #include <iostream>
    using namespace std;
    //继承中的同名静态成员处理方式
    
    class Base {
        public:
            static int m_A;
    };
    int Base::m_A = 100;
    
    class Son: public Base {
        public:
    
            static int m_A;
    };
    int Son::m_A = 200;
    
    //同名静态成员属性
    void test01() {
        Son s;
        //1.通过对象访问
        cout << "Son 下 m_A = " << s.m_A << endl;
        cout << "Base 下 m_A = " << s.Base::m_A << endl;
        //2.通过类名访问
        cout << "Son 下 m_A = " << Son::m_A << endl;
        cout << "Base 下 m_A = " << Base::m_A << endl;
        //第一个::代表通过类名方式访问,第二个::代表访问父类作用域下
        cout << "通过子类访问父类m_A = " << Son::Base::m_A << endl;
    }
    
    int main() {
        test01();
        return 0;
    }

    ②同名静态成员函数

    #include <iostream>
    using namespace std;
    //继承中的同名静态成员处理方式
    class Base {
        public:
            static int m_A;
    
            static void func() {
                cout << "Base static void func()" << endl;
            }
            static void func(int a) {
                cout << "Base static void func(int a)" << endl;
    
            }
    };
    int Base::m_A = 100;
    
    class Son: public Base {
        public:
            static void func() {
                cout << "Son static void func()" << endl;
            }
            static int m_A;
    };
    int Son::m_A = 200;
    
    //同名静态成员属性
    void test01() {
        Son s;
        //1.通过对象访问
        s.func();
        s.Base::func();
        //2.通过类外访问
        Son::func();
        Base::func();
        Son::Base::func();
        Son::Base::func(100);
    }
    
    int main() {
        test01();
    
        return 0;
    }

    6)多继承语法

    class   子类:  继承方式   父类1,继承方式   父类2,。。。

    多继承可能会引发父类中有同名成员出现,需要加作用域区分。实际开发中不建议用多继承

    7)菱形继承与虚继承

    ①概念:2个派生类继承自同一个基类,又有同一个类继承这2个派生类,这种继承被称为菱形继承,或钻石继承。

    ②菱形继承的问题:这种继承方式也存在数据的二义性,这里的二义性是由于他们间接都有相同的基类导致的。 这种菱形继承除了带来二义性之外,还会浪费内存空间。

    ③解决方法:虚继承

    class A
    {
    public :
        int num;
        A()
        {
            num = 10;
        }
    };
    
    class B :virtual public A
    {
    public:
        B()
        {
            num = 20;
        }
    };
    
    class C :virtual public A
    {
    public:
        C()
        {
            num = 30;
        }
    };
    
    class D :public B, public C
    {
    public:
        D()
        {
            num = 50;
        }
    };
    
    int main()
    {
        D d;
        cout << d.num << endl;
        system("pause");
        return 0;
    }

    六、多态

     1)分类(2类)

    ①静态多态:函数重载以及运算符重载属于静态重载,复用函数名。

    ②动态多态:派生类和虚函数实现运行时多态。

    2)动态多态代码实例

    动态多态满足条件:①有继承关系;②子类重写父类虚函数。

    class Father
      {
      public:
          void Face()
         {
             cout << "Father's face" << endl;
         }
     
         virtual void Say()
         {
             cout << "Father say hello" << endl;
         }
     };
     
     
     class Son:public Father
     {
     public:     
         void Say()
         {
             cout << "Son say hello" << endl;
         }
     };
     
     void main()
     {
         Son son;
         Father *pFather=&son; // 隐式类型转换
         pFather->Say();
     }

     3)纯虚函数和抽象类

    ①纯虚函数语法:virtual 返回类型 函数名(参数列表)=0

    ②抽象类概念:只要有一个纯虚函数,这个类就称为抽象类。

    ③抽象类特点:1)无法实例化对象;2)抽象类的子类必须要重写父类中的纯虚函数,否则也属于抽象类。

    ④代码实例:

    class A
    {
    public :
        int num;
        //纯虚函数
        virtual void func() = 0;
    };
    
    class B :public A
    {
    public:
        virtual void func(){}
    };

    4)虚析构和纯虚析构

    虚析构和纯虚析构可以解决父类指针释放子类对象时不干净的问题。

    纯虚析构需要声明也需要实现。

     

  • 相关阅读:
    【软件测试】3.深入了解软件测试基础day3
    【软件测试】3.深入了解软件测试基础day2
    【软件测试】3.深入了解软件测试基础day1
    【软件测试】3.Linux介绍、命令
    【软件测试】1.软件测试前置基础知识
    玩转数据结构:第8章 优先队列和堆
    一、VIP课程:互联网工程专题 05-快速掌握Jenkins原理与核心功能
    Sublime 一些常用快捷键
    前端01 HTML5
    ios 故事版
  • 原文地址:https://www.cnblogs.com/mango1997/p/14174173.html
Copyright © 2020-2023  润新知