美文网首页
static,const,拷贝,友元,模板

static,const,拷贝,友元,模板

作者: SeanLink | 来源:发表于2022-03-09 15:56 被阅读0次

    静态成员 static

    1. 静态成员:被static修饰的成员变量\函数
      可以通过对象(对象.静态成员)、对象指针(对象指针->静态成员)、类访问(类名::静态成员)
    2. 静态成员变量
      存储在数据段(全局区,类似于全局变量),整个程序运行过程中只有一份内存
      对比全局变量,它可以设定访问权限(public、protected、private),达到局部共享的目的
      必须初始化,必须在类外面初始化,初始化时不能带static,如果类的声明和实现分离(在实现.cpp中初始化)
    3. 静态成员函数
      内部不能使用this指针(this指针只能用在非静态成员函数内部)
      不能是虚函数(虚函数只能是非静态成员函数)
      内部不能访问非静态成员变量\函数,只能访问静态成员变量\函数
      非静态成员函数内部可以访问静态成员变量\函数
      构造函数、析构函数不能是静态
      当声明和实现分离时,实现部分不能带static

    const成员

    1. const成员:被const修饰的成员变量、非静态成员函数
    2. const成员变量
      必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
      非static的const成员变量还可以在初始化列表中初始化
    3. const成员函数(非静态)
      const关键字写在参数列表后面,函数的声明和实现都必须带const
      内部不能修改非static成员变量
      内部只能调用const成员函数、static成员函数
      非const成员函数可以调用const成员函数
      const成员函数和非const成员函数构成重载
      非const对象(指针)优先调用非const成员函数
      const对象(指针)只能调用const成员函数、static成员函数

    引用成员类型

    引用类型成员变量必须初始化(不考虑static情况)

    1. 在声明的时候直接初始化
    2. 通过初始化列表初始化

    拷贝构造函数

    拷贝构造函数是构造函数的一种
    当利用已存在的对象创建一个新对象时(类似于拷贝),就会调用新对象的拷贝构造函数进行初始化
    拷贝构造函数的格式是固定的,接收一个const引用作为参数

    class Car {
        int age;
        int& m_price = age;
    public:
        Car(int& price) : m_price(price) {};
            //拷贝构造函数
            Car(const Car& car) {
            this->m_price = car.m_price;
            }
    };
    

    调用父类的拷贝构造函数

    class Person{
        int m_age;
    public:
        Person(int age) :m_age(age) {};
        Person(const Person& person) : m_age(person.m_age) {}
    };
    
    class Student : public Person {
        int m_score;
    public:
        Student(int age, int score) : Person(age), m_score(score) {}
        Student(const Student& student) : Person(student), m_score(student.m_score) {};
    };
    

    深拷贝

    class Car {
        int m_price;
        char* m_name;
        void copyName(const char* name) {
            if (name == nullptr) return;
            // 申请新的堆空间
            this->m_name = new char[strlen(name) + 1]{};
            // 拷贝字符串数据到新的堆空间
            strcpy(this->m_name, name);
        }
    public:
        Car(int price = 0, const char* name = nullptr) :m_price(price) {
            copyName(name);
        }
        Car(const Car& car) {
            this->m_price = car.m_price;
            copyName(car.m_name);
        }
        ~Car() {
            if (m_name != nullptr)
            {
                delete[] m_name;
                m_name = nullptr;
            }
        }
    };
    

    对象类型的参数和返回值

    下面会产生匿名对象(临时对象):没有变量名、没有被指针指向的对象,用完后马上调用析构

    Car test(Car car) {
        Car car1(20);
        return car1;
    }
    

    隐式构造函数

    Car定义在上面,像这种写法就属于隐式构造
    关键字 explicit 可以禁用隐式构造

    Car car = 10;
    Car car2 = car;
    //打印地址
    cout << &car << "\n" << &car2 << endl;
    

    编译器是否会自动生成构造函数?

    不会自动生成构造函数,只会在有某些操作下才会生成:

    1. 成员变量在声明的同时进行了初始化
    2. 有定义虚函数
    3. 虚继承了其他类
    4. 包含了对象类型的成员,且这个成员有构造函数(编译器生成或自定义)
    5. 父类有构造函数(编译器生成或自定义)
      总结就是:
      对象创建后,需要做一些额外操作时(比如内存操作、函数调用),编译器一般都会为其自动生成无参的构造函数

    友元

    声明为友元函数或者友元类就可以访问类的私有属性或者方法

    class Person {
        friend class Cat;
        friend int getAge(Person person);
    private:
        int m_age;
        int m_height;
    };
    
    class Cat {
    public:
        void eat() {
            Person person;
            person.m_age = 10;
            person.m_height = 20;
            int age = getAge(person);
            cout << age << endl;
        }
    };
    
    int getAge(Person person) {
        return person.m_age;
    }
    

    内部类

    顾名思义就是嵌套的类

    class Point {
        class Math {
            //声明1
            void test();
        };
        //声明2
        class Add;
        class Move;
    };
    
    //实现1
    void Point::Math:: test(){
    }
    //实现2
    class Point::Add {
        void test() {}
    };
    //实现3
    class Point::Move {
        void test() {
        }
    };
    

    局部类

    定义在函数代码里面的类

    1. 作用域仅限于所在的函数内部
    2. 其所有的成员必须定义在类内部,不允许定义static成员变量
    3. 成员函数不能直接访问函数的局部变量(static变量除外
    void test() {
        class Dog {
            public:
                int age;
        };
        Dog dog;
        dog.age = 2;
    }
    

    模板(template)

    template <typename T> 或 <class T> 两者是等价的.
    使用模板需要注意:

    1. 模板没有被使用时,是不会被实例化出来的
    2. 模板的声明和实现如果分离到.h和.cpp中,会导致链接错误
    3. 一般将模板的声明和实现统一放到一个.hpp文件中
      函数模板
    //单类型
    template <class T> void swapValues(T& v1, T& v2) {
        T temp = v1;
        v1 = v2;
        v2 = temp;
    }
    //多类型
    template <class T1, class T2> 
    void display(const T1& v1, const T2& v2) {
        cout << v1 << endl;
        cout << v2 << endl;
    }
    

    类模板

    #pragma once
    #include <iostream>
    using namespace std;
    
    template <typename Item>
    class Array {
        //重载打印函数
        friend ostream& operator<<<>(ostream&, const Array<Item>&);
        //指向首元素
        Item* m_data;
        //元素个数
        int m_size;
        //容量
        int m_capacity;
        void checkIndex(int index);
    public:
        Array(int capacity = 0);
        ~Array();
        void add(Item value);
        void remove(int index);
        void insert(int index, Item value);
        Item get(int index);
        int size();
        Item operator[](int index);
    };
    
    template <typename Item>
    Array<Item>::Array(int capacity) {
        m_capacity = (capacity > 0) ? capacity : 10;
        //申请堆空间
        m_data = new Item[m_capacity];
    }
    
    template <typename Item>
    Array<Item>::~Array() {
        if (m_data == nullptr) return;
        delete[] m_data;
    }
    
    template <typename Item>
    void Array<Item>::checkIndex(int index) {
        if (index < 0 || index >= m_size) {
            // 报错:抛异常
            throw "数组下标越界";
        }
    }
    
    template <typename Item>
    ostream& operator<<<>(ostream& cout, const Array<Item>& array) {
        cout << "[";
    
        for (int i = 0; i < array.m_size; i++) {
            if (i != 0) {
                cout << ", ";
            }
            cout << array.m_data[i];
        }
    
        return cout << "]";
    }
    
    template <typename Item>
    void Array<Item>::add(Item value) {
        if (m_size == m_capacity) {
            // 扩容
            /*
            1.申请一块更大的新空间
            2.将旧空间的数据拷贝到新空间
            3.释放旧空间
            */
            cout << "空间不够" << endl;
            return;
        }
    
        m_data[m_size++] = value;
    }
    

    相关文章

      网友评论

          本文标题:static,const,拷贝,友元,模板

          本文链接:https://www.haomeiwen.com/subject/glwnrrtx.html