C++基础复习3

#include 
#include 


using namespace std;


/*
OOP的三大特性:封装 继承 多态


封装:
    将静态属性和动态行为封装成一个整体
    属性和行为加以权限控制:public private protect
        public:类外 类内都可访问
        private:类外不可访问 类内可以访问
        protect:类外不可访问 类内可以访问


    struct与class的区别:struct默认权限是public class的默认权限是private


构造函数:创建对象时,为对象的成员属性赋初始值,构造函数由编译器自行调用
    1.无返回值
    2.函数名与类名相同
    3.可以进行函数重载,可以有参数
    4.每次创建调用时会自动调用构造函数,且只会调用一次


构造函数的分类:
    1.按参数分类:有参构造函数 无参构造函数
    2.按类型分类:普通构造函数 拷贝构造函数

构造函数的调用方式: 括号法  显示法  隐式转换法




拷贝构造函数调用时机:
    1.用一个已有对象去初始化一个新的对象;
    2.值传递的方式给函数参数传递值;
    3.以值传递方式返回局部对象;




构造函数的调用规则:
    1.默认情况下,c++编译器至少给一个类添加3个函数:默认构造函数(无参数) 默认析构函数(无参数) 默认拷贝构造函数(对属性进行值拷贝)
    2.如果用户定义了有参构造函数,c++不会再提供无参数的默认构造函数,但是会提供默认拷贝构造函数;
    3.如果用户定义了拷贝构造函数,c++不会再提供其他构造函数;



析构函数:销毁对象前,系统自动调用清理内存
    1.无返回值
    2.函数名与类名相同,且加上~
    3.析构函数无参数,不可以进行函数重载
    4.对象销毁前会自动调用析构函数


// 浅拷贝与深拷贝
    // 浅拷贝:简单的赋值拷贝操作
    // 深拷贝:在heap上重新申请空间,进行拷贝操作


// 类对象作为类成员:C++中类的成员可以是另一个类的对象,称为对象成员
class A{

};

// 创建B对象时,A和B的构造函数与析构函数谁先谁后呢?---先调用对象成员的构造函数,再调用本类的构造函数
class B{
public:
    A a;
};



// 必须使用列表初始化的场景:
    注意:成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的
    1.常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
    2.引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
    3.没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。



// 静态成员:在成员变量或成员函数前加上static关键字

静态成员分为:
    静态成员变量:
        1.所有对象共享同一份数据
        2.在编译阶段分配内存
        3.类内声明,类外进行初始化
    
    静态成语函数:
        1.所有对象共享同一个函数
        2.静态成员函数只能访问静态成员变量

*/

const double PI = 3.14;

class Circle{
public:

    explicit Circle(int r):m_r(r) {}

    virtual ~Circle(){}

    double calculateZC() {
        return 2 * PI * m_r;
    }

private:
    int m_r;
};




class Student {
public:
    Student(string name, int age, int id):m_name(name) ,m_age(age), m_id(id) {}

    ~Student() {}

    void showStudentInfo() {
        cout << m_name << "  " << m_age << "  " << m_id << endl;
    }

    int m_aa;
private:
    string m_name;
    int m_age;
    int m_id;
};


// 构造函数的分类及调用

class Person{
public:
    // 无参数的构造函数
    Person() {
        cout << "not params\n";
    }

    // 有参的构造函数
    Person(int age): m_age(age) {
        cout << "display params age\n";
    }


    // 拷贝构造函数
    Person(const Person& p) {
        m_age = p.m_age;
        cout << "copy constructor has been called\n";
    }
    

    // 析构函数
    ~Person(){
        cout << "deconstructor function\n";
    }


public:
    int m_age;
};


// 1.使用一个已初始化的对象来初始化一个新对象
void test01() {
    Person man(100);  // man是一个已经创建好的对象
    Person newman(man); // 调用拷贝构造函数
    Person newman2 = man;  // 调用拷贝构造函数

    // Person newman3;   
    // newman3 = man;  // 不调用拷贝构造函数,只是普通赋值操作
}


// 2.以值传递的方式给函数传递参数
void doWork(Person p) {
    cout << "doWork: " << (int*)&p << endl;
}

void test02(){
    Person p;  // 无参构造函数
    doWork(p);
}



// 3.以值传递的方式返回局部对象
Person doWork2() {
    Person p1;
    cout << "doWork2: " << (int*)&p1 << endl;
    return p1;
}

void test03() {
    Person p = doWork2();
    cout << "test03: " << (int*)&p << endl;
}


// 构造函数的调用规则
void test04() {
    Person p1(18);
    // 如果不写拷贝构造函数,编译器会自动添加拷贝构造函数,并且做浅拷贝操作
    Person p2(p1);
    cout << "p2 age is: " << p2.m_age << endl; 

}


// 浅拷贝与深拷贝
class Test {
public:
    // 默认构造函数
    Test() {
        cout << "默认构造函数\n";
    }

    // 用户自定义构造函数
    Test(int age, int height) {
        m_age = age;
        m_height = new int (height);
    }

    // 拷贝构造函数
    Test(const Test& t) {
        cout << "Test copy structor\n";
        m_age = t.m_age;
        m_height = new int (*t.m_height);
    }

    // 析构函数
    ~Test() {
        cout << "Test deconstructor function\n";
        if(m_height) {
            delete m_height;
        }
    }


    int m_age;
    int* m_height;
};


// 如果对象的属性中有在heap上开辟的,一定要自己提供拷贝构造函数,不能使用默认的拷贝构造函数(浅拷贝)
void test05() {
    Test t1(18, 172);
    Test t2(t1);
    
    cout << "t1.age=" << t1.m_age << " *t1.m_height=" << *t1.m_height << endl;
    cout << "t2.age=" << t2.m_age << " *t2.m_height=" << *t2.m_height << endl;
}



// 类对象作为类成员
class Phone {
public:
    Phone(string name) {
        m_name = name;
        cout << "Phone constructor\n";
    }

    ~Phone() {
        cout << "Phone deconstructor\n";
    }

    string m_name;
};


class Curry {
public:
    Curry(string name, string pName): m_name(name), m_phone(pName) {
        cout << "Curry constructor\n";
    }

    ~Curry() {
        cout << "Curry deconstructor\n";
    }

    void playGame(){
        cout << m_name << " is using " << m_phone.m_name << " play games\n";
    }


    string m_name;
    Phone m_phone;  // 类中成员m_phone是Phone类的对象时,此时m_phone称为对象成员
};


void test06() {
    // 构造顺序:先调用对象成员的构造函数,再调用本类的构造函数;析构对象时顺序相反
    Curry cu("Curry", "xiaomi");
    cu.playGame();
}




// 静态成员变量与静态成员函数
    // 静态成员变量
        // 1.所有对象共享同一份数据
        // 2.在编译阶段分配内存
        // 3.类内声明,类外初始化

    // 静态成员函数
        // 1.所有对象共享同一个函数
        // 2.静态成员函数只能访问静态成员变量
class Hello{
public:
    static int m_H;  // 静态成员变量

    int m_HO;  // 普通成员变量

    // 静态成员函数
    static void func1(){
        cout << "func1 is called\n";
        m_H = 666;  // 静态成员函数只能访问静态成员变量
        // m_HO = 721; 错误,不可访问非静态成员变量
    }
private:
    static int m_L;

    static void func2() {
        cout << "func2 is called\n";
    }
};

// 静态成员变量在类外初始化
int Hello::m_H = 100;
int Hello::m_L = 102;

// 静态成员变量的访问方式
void test07() {
    // 1.通过对象
    Hello h;
    h.m_H = 134;
    cout << "h.m_H =" << h.m_H << endl;

    Hello h1;
    h1.m_H = 999;
    // 共享同一份数据
    cout << "h.m_H =" << h.m_H << endl;
    cout << "h1.m_H =" << h1.m_H << endl;


    // 2.类名直接访问
    cout << "h.m_H =" << Hello::m_H << endl;

    // 静态成员函数的访问方式
    // 1.通过对象
    Hello h2;
    h2.func1();

    cout << "h2.m_H =" << h2.m_H << endl;
    
    
    // 2.通过类名
    Hello::func1();
    // Hello::func2();  没有访问权限
    cout << "Hello::m_H =" << Hello::m_H << endl;
}

// C++中的对象模型和this指针
    // 1.在c++中,类内的成员变量和成员函数分开存储
    // 2.只有非静态成员变量才属于类的对象上

class Student1{
public:
    Student1() {
        m_id = 0;
    }

    // 普通成员函数也不占用对象空间,所有函数共用一个函数实例
    void func() {
        cout << "m_id = " << this->m_id << endl;
    }

    // 静态成员函数不占用对象空间
    static void sfunc() {   
        cout << "TODO\n";
    }

private:
    // 非静态成语变量占用对象空间
    double m_id;
    // 静态成员变量不占用对象空间
    static int m_tel;
};


// this指针概念:
    // cpp中成员变量和成员函数是分开存储的----->每个非静态成员函数只会产生一份函数实例,即多个同类型的对象会共用一块代码
    // -------->同一块非静态成员函数代码如何区分哪个对象调用自己的?
    // cpp通过特殊的对象指针this解决,this指针指向被调用的成员函数所属的对象
    // this指针是隐含每一个非静态成员函数内的一种指针;
    // this指针用途:当形参和成员变量同名时,可以用this指针来区分;在类的非静态成员函数中返回对象本身return *this
class Teacher{
public:
    Teacher(int age) {
        // 1.当形参和成员变量同名时,用this指针来区分
        this->age = age;
    }

    Teacher(const Teacher& t) {
        cout << "teacher copy constructor\n";
    }

    Teacher& TeacherAddTeacher(Teacher t){  // 会调用拷贝构造函数
        this->age += t.age;
        // 2.返回对象本身
        return *this;
    }

    int age;
};

// 空指针访问成员函数
// cpp中空指针也是可以访问成员函数的,注意有没有用到this指针,如果用到则需要加判断来保证代码的健壮性
class Player{
public:
    void showClassName(){
        cout << "Class Player\n";
    }

    void showPlayer(){
        if(this == nullptr) return;
        cout << mAge << endl;
    }
public:
    int mAge;
};


void test11() {
    Player* p = nullptr;
    p->showClassName();  // 空指针,可以调用成员函数
    p->showPlayer();  // 但是如果成员函数中用到了this指针,就不可以了
}

// const修饰成员函数
    // 常函数:
        // 成员函数后加const后这个函数称为常函数
        // 常函数内部不可以修改成员属性
        // 成员属性声明时加关键字mutable时,在常函数内部依然可以修改
    
    // 常对象:
        // 声明对象前加const称此对象是常对象
        // 常对象只能调用常函数

class Const{
public:
    Const(){
        m_A = 0;
        m_B = 0;
    }

    // this指针的本质是一个指针常量,指针的指向不可以改变
    // 如果希望指针指向的值也不可以修改,需要声明为常函数
    void showConst() const {

        // const修饰成员函数,表示指针指向的内存空间的数据不能被修改,除了mutable修饰的变量
        this->m_B = 100;
    }

    void MyFunc() const {
        // m_A = 100;
    }

public:
    int m_A;
    mutable int m_B;
};

void test22() {
    const Const cs;  // 常对象cs
    cout << cs.m_A << endl;
    // cs.mA = 100; 常对象不能修改成员变量的值,但可以访问
    
    cs.m_B = 1000;
    cs.MyFunc(); // 常对象只能访问常成员函数

}



int main() {
    
    // Circle c(2); 显式

    // Circle c = 10;  隐式

    Circle c(10);

    cout << "ZC is: " << c.calculateZC() << endl;\


    Student stu("zhangsan", 18, 1120001);
    stu.showStudentInfo();

    // stu.m_name; 类外不可以访问
    // stu.m_aa;  类外可以访问



    // 构造函数的分类及调用

    Person p; // 调用无参构造函数
    Person p1(10);  // 括号法  显示法
    Person p2 = 20;  // 隐式转换法

    Person p3 = Person(18);

    Person p4 = p2;  // 调用拷贝构造函数

    test02();
    test03();

    cout << "--------test04---------\n";
    test04();

    cout << "--------Test---------\n";
    test05();

    cout << "--------test06---------\n";
    test06();


    cout << "--------test07---------\n";
    test07();

    cout << "--------test08---------\n";
    cout << "sizeof(Student1) = " << sizeof(Student1) << endl;

    cout << "--------test09---------\n";
    Student1 s1;
    s1.func();

    cout << "--------test10---------\n";
    Teacher t1(24);
    cout << "t1.age = " << t1.age << endl;

    cout << "-----split line---------\n";
    Teacher t2(35);
    t2.TeacherAddTeacher(t1).TeacherAddTeacher(t1).TeacherAddTeacher(t1);
    cout << "t2.age = " << t2.age << endl;

    cout << "--------test11---------\n";
    test11();
    cout << "--------test22---------\n";
    test22();

    return 0;
}

你可能感兴趣的:(C++基础复习3)