03 面向对象

1、封装

1.1 属性和行为

cpp 复制代码
#include <iostream>
using namespace std;

// 面向对象三大特性:封装、继承、多态

/*
封装的语法:

class 类名 {
访问权限:
    属性(成员变量)
    行为(成员函数)
};
*/

class Hero {
    // 访问权限  public private protected
public:
    // 属性
    int   m_Id;   // m -> member
    int   m_Hp;

    // 行为
    void addHp(int hp) {
        m_Hp += hp;
    }

    void subHp(int hp) {
        m_Hp -= hp;
    }
};

int main() {
    // 通过类来生成对象的过程,叫  实例化
    Hero h;
    // 访问对象的属性
    h.m_Id = 5;
    h.m_Hp = 100;
    h.addHp(100);
    cout << "Id 为" << h.m_Id << "的英雄,血量是" << h.m_Hp << endl;
    h.subHp(100);
    cout << "Id 为" << h.m_Id << "的英雄,血量是" << h.m_Hp << endl;

    return 0;
}

1.2 访问权限

cpp 复制代码
#include <iostream>
using namespace std;

/*
访问权限
公共权限   public         类内可以访问,类外也可以访问
保护权限   protected      类内可以访问,类外不可以访问    子类可以访问
私有权限   private        类内可以访问,类外不可以访问    子类不可以访问(继承)

B -> A

A  父类、基类       名字、房子、支付密码
B  子类、派生类     公有、保护、私有

*/

class People {
    // 公有权限
public:
    int m_Id;

    // 保护权限
protected:
    int m_HouseId;

    // 私有权限
private:
    int m_PayPass;

public:
    void work() {
        // 所有成员变量,类内均可以访问
        m_Id = 1;
        m_HouseId = 2;
        m_PayPass = 1314;
    }
private:
    void work1() {
        // 所有成员变量,类内均可以访问
        m_Id = 1;
        m_HouseId = 2;
        m_PayPass = 1314;
    }

};


class Son : public People {
    void func() {
        m_Id = 1;
        m_HouseId = 4;    // 保护成员,子类可以访问
        // m_PayPass = 123;  // 私有成员,子类无法访问
        People::work();
       // People::work1();//私有成员,子类无法访问
    }
};

int main() {
    // 实例化
    People p;
    p.m_Id = 1;       // 公有成员,类外可以访问
    //p.m_HouseId = 5;  // 保护成员,类外不可以访问
    //p.m_PayPass = 10; // 私有成员,类外不可以访问
    p.work();
    // p.work1();        // 私有成员函数,类外不可访问
    return 0;
}

1.3class和struct

cpp 复制代码
#include <iostream>
using namespace std;

/*
struct && class

struct 默认是公共的
class  默认是私有的
*/

class C {
    int m_a;
};

struct S {
    int m_a;

    void func() {   //c和c++区别 c不能定义函数
        m_a = 666;
    }
};

int main() {
    C c;
    S s;
    // c.m_a;      // 私有的
    s.m_a = 4;  // 公有的
    s.func();
    cout << s.m_a << endl;//666

    return 0;
}

1.4 属性私有化

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 接口、方法、函数 是同一个概念
// 1、可以控制读写权限
// 2、可以检测数据的有效性

class Hero {
public:
    //方法来访问属性成员变量
    void SetName(string name) {  //设置
        m_Name = name;
    }
    string GetName() {  //获取
        return m_Name;
    }

    int GetSkillCount() {
        return m_SkillCount;
    }

    void SetSpeed(int speed) {  //设置
        if (speed < 100 || speed > 500) {
            cout << "速度设置不合法" << endl;
            return;
        }
        m_Speed = speed;
    }

private:
    string   m_Name;            // 可读,可写
    int      m_SkillCount = 4;  // 只读
    int      m_Speed;           // 只写
};

int main() {
    Hero h;
    /*   不行,访问不了
        h.m_Name = "123";
        h.m_SkillCount = 4;
        h.m_Speed = 10;
    */
    h.SetName("剑圣");
    cout << "英雄的名字叫:" << h.GetName() << endl;
    cout << "英雄的技能数是:" << h.GetSkillCount() << endl;
    h.SetSpeed(666);

    return 0;
}

2、对象特性

2.1构造函数

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;


/*
构造函数需要注意的点

1、函数名称和类名保持一致
2、返回值类型 不需要写
3、构造函数可以有参数
*/
class Hero {
public:
    // 默认构造函数
   /* Hero() {
        m_Name = "";
        m_SkillCount = 4;
        m_Speed = 100;
        cout << "默认构造函数:Hero 构造完毕!" << endl;
    }*/

    // 有参构造函数1
    Hero(string name="123") {  //加了"123"    Hero h1;也调用
        m_Name = name;
        m_SkillCount = 4;
        m_Speed = 100;
        cout << "有参构造函数1:Hero 构造完毕!" << endl;
    }
    // 有参构造函数2
    Hero(string name , int skillCount) {
        m_Name = name;
        m_SkillCount = skillCount;
        m_Speed = 100;
        cout << "有参构造函数2:Hero 构造完毕!" << endl;
    }

    
private:
    string   m_Name;
    int      m_SkillCount;
    int      m_Speed;
};

int main() {
    Hero h1;
    Hero h2("剑圣");
    Hero h3();   // 函数声明  像int main(); int work(); 没调任何构造函数
    Hero h4{};
    Hero h5 = Hero("剑圣");
    Hero h6{ "猴子", 4 };

    return 0;
}
/*
默认构造函数:Hero 构造完毕!
有参构造函数1:Hero 构造完毕!
默认构造函数:Hero 构造完毕!
有参构造函数1:Hero 构造完毕!
有参构造函数2:Hero 构造完毕!
*/

2.2析构函数

cpp 复制代码
#include <iostream>
using namespace std;

/*
析构函数注意点

1、函数名称和类名一致,并且在最前面加上一个 ~ 波浪号
2、函数返回值不需要写
3、不能有参数

*/
class Hero {
public:
    // 构造函数  对象创建
    Hero() {
        cout << "Hero 默认构造函数调用完毕!" << endl;
    }
    // 析构函数   对象销毁
    ~Hero() {
        cout << "Hero 析构函数调用完毕!" << endl;
    }
};

void test() {
    Hero h;
}

int main() {
    test();
    Hero h;
    int a;
    cin >> a;
    return 0;
}
/*
Hero 默认构造函数调用完毕!
Hero 析构函数调用完毕!
Hero 默认构造函数调用完毕!
12
Hero 析构函数调用完毕!
*/

2.3拷贝构造函数

cpp 复制代码
#include <iostream>
using namespace std;


/*
拷贝构造函数的定义
类名(const 类型& 变量名) {}

*/
class Hero {
public:
    // 默认构造函数
    Hero() {
        m_Hp = 100;
        cout << "Hero 默认构造函数调用完毕!" << endl;
    }

    // 有参构造函数
    Hero(int hp) {
        m_Hp = hp;
        cout << "Hero 有参构造函数调用完毕!" << endl;
    }

    //拷贝构造函数
    Hero(const Hero& h) {
       // h.m_Hp = 4;//不可以
        m_Hp = h.m_Hp;
        cout << "Hero 拷贝构造函数调用完毕!" << endl;
    }

    // 析构函数
    ~Hero() {
        cout << "Hero 析构函数调用完毕!" << endl;
    }

private:
    int   m_Hp;
};


/*
拷贝构造函数的调用时机

1、用已经创建的对象来初始化对象
2、函数的传参
3、函数的返回值

*/

// 1、用已经创建的对象来初始化对象
void func1() {
    cout << "--------------func1--------------" << endl;
    Hero h1(20);
    Hero h2(h1);
}

// 2
void test1(Hero h) {

}

void test2(Hero* h) {

}

// 2、函数的传参
void func2() {
    cout << "--------------func2--------------" << endl;
    Hero h1;
    // test1(h1);//调拷贝
    test2(&h1);//传指针,没有生成对象,不调用拷贝
}

// 3、函数的返回值
Hero test3() {
    Hero h(40);
    return h;
}

void func3() {
    cout << "--------------func3--------------" << endl;
    Hero h = test3(); //会优化,不调用拷贝构造函数, 
    //解决:右键点击属性->c/c++->命令行 /Zc:nrvo-
}

int main() {
    func1();
    func2();
    func3();
    return 0;
}

2.4初始化列表

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

/*
初始化列表的语法

构造函数(传参1, 传参2): 成员变量1(传参1), 成员变量2(传参2) {}

*/
class Hero {
public:
    /*Hero(string name, int hp) {
        m_Name = name;
        m_Hp = hp;
    }*/
    Hero(string name, int hp, int speed) : m_Name(name), m_Hp(hp), m_Speed(speed) {
    }

    void Print() {
        cout << "英雄:" << m_Name << "的血量是" << m_Hp << ",速度是" << m_Speed << endl;
    }

private:
    string m_Name;
    int m_Hp;
    int m_Speed;
};
int main() {
    Hero h("剑圣", 100, 10);
    h.Print();

    return 0;
}

2.5静态成员变量

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

/*
静态成员变量的特点:
1、所有的对象共享同一份数据
2、编译阶段分配内存
3、需要在类中进行声明,在类外进行初始化
*/
class Hero {
public:
    Hero() {
        m_Name = "英雄";
        m_Hp = 100;
    }

    ~Hero() {

    }
    // 3.1 声明
    static int m_HeroCount;
private:
    string m_Name;
    int m_Hp;
    
};

// 3.2 初始化
int Hero::m_HeroCount = 100;//作用域 Hero::

int main() {
    Hero h;
    cout << h.m_HeroCount << endl;//1  100
    h.m_HeroCount = 101;
    cout << Hero::m_HeroCount << endl;//2  101

    cout << &(h.m_HeroCount) << endl;//00007FF6BC742000
    cout << &(Hero::m_HeroCount) << endl;//00007FF6BC742000  同一个变量
    return 0;
}

2.6静态成员函数

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

/*
静态成员函数
1、所有对象共享函数
2、静态成员函数只能使用静态成员变量,无法使用普通成员变量
*/

class Hero {
public:
    Hero() {
        m_Name = "英雄";
        m_Hp = 100;
    }
    ~Hero() {

    }

    static int m_HeroCount;

    static int GetHeroCount() {  //静态成员函数
        //m_Hp += 1;
        return m_HeroCount;
    }
private:
    string   m_Name;
    int      m_Hp;


    static int GetHeroCount1() {
        // m_Hp += 1;
        return m_HeroCount;
    }
};

int Hero::m_HeroCount = 100;

int main() {
    Hero h;
    cout << h.GetHeroCount() << endl;
    cout << Hero::GetHeroCount() << endl;
    //h.GetHeroCount1();//拿不了
    return 0;
}

2.7 this指针

cpp 复制代码
#include <iostream>
using namespace std;

/*
this指针
1、解决命名冲突
2、*this 就可以获取到这个对象本身

this     *this
 &h      *(&h) == h

*/

class Hero {
public:
    Hero(int hp) {
        //hp = hp;//形参覆盖实参
        this->hp = hp;
        cout << this << endl;//地址  000000BFDDF1F984
        cout << (*this).hp << endl;//100
    }
    int hp;
};

int main() {
    Hero h(100);
    cout << h.hp << endl;//100
    cout << &h << endl;  //000000BFDDF1F984  一样
    cout << (*(&h)).hp << endl;//100
    return 0;
}

2.8 const修饰成员函数

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

// 常函数

class Hero {
public:
    Hero() : m_Hp(0) {}

    int getHp() const {
        // m_Hp = m_Hp + 1;//无法修改成员变量的值
        return m_Hp;
    }
    int setHp(int hp) {
        m_Hp = hp;
    }
private:
    int m_Hp;
};


int main() {
    const Hero h;//不能被修改
    // h.setHp(100);//常量不能调用非常量函数
    h.getHp();
    return 0;
}

2.9 mutable关键字

cpp 复制代码
#include <iostream>
using namespace std;

// mutable 可变  <-> const

class Hero {
public:
    Hero() :m_Hp(0), m_getHpCounter(0) {}

    int getHp() const {
        m_getHpCounter++;
        return m_Hp;
    }

    void printCounter() const {
        cout << "Counter: " << m_getHpCounter << endl;
    }

private:
    int m_Hp;
    mutable int m_getHpCounter;//const函数里可操作
};

int main() {
    Hero h;
    h.getHp(), h.getHp(), h.getHp(), h.getHp(), h.getHp(), h.getHp();//调6次
    h.printCounter();

    return 0;
}

3、友元

3.1全局函数作为友元

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

/*
友元的目的

让一个类 或者 函数
能够访问另一个类的私有成员

友元的关键字: friend

三种友元
1、全局函数作为友元
2、类作为友元
3、成员函数作为友元
*/

class People {
    friend void friendVisit(People* p);
public:
    People() {
        m_House = "别墅";
        m_Car = "跑车";
    }
public:
    string    m_House;

private:
    string   m_Car;
};

void friendVisit(People* p) {
    cout << "好朋友来访问你的" << p->m_House << endl;
    cout << "好朋友来访问你的" << p->m_Car << endl;//私有成员访问
}

int main() {
    People p;
    friendVisit(&p);
    return 0;
}

3.2类作为友元

cpp 复制代码
#include <iostream>
using namespace std;

// 类作为友元
// 让一个类去访问另一个类的私有成员

class People;//声明

class PeopleFriend {
public:
    PeopleFriend() {

    }
    void visit(People* p);
    /*void visit(People* p) {
        cout << "好朋友来访问你的" << p->m_House << endl;
        cout << "好朋友来访问你的" << p->m_Car << endl;//m_House,m_Car 还没执行到,不知道,放在后面实现
    }*/
};

class People {
    friend class PeopleFriend;//访问私有
public:
    People() {
        m_House = "别墅";
        m_Car = "跑车";
    }
public:
    string    m_House;

private:
    string    m_Car;
};

//函数实现
void PeopleFriend::visit(People* p) {
    cout << "好朋友来访问你的" << p->m_House << endl;
    cout << "好朋友来访问你的" << p->m_Car << endl;
}

int main() {
    People p;
    PeopleFriend pf;
    pf.visit(&p);
    return 0;
}

3.3成员函数作为友元

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

//  成员函数作为友元
// PeopleFriend 的某个函数能够访问  People 的私有成员变量

class People;

class PeopleFriend {
public:
    PeopleFriend() {}

    void visitAll(People* p);
    void visitPub(People* p);
};


class People {
    // friend class PeopleFriend;
    friend void PeopleFriend::visitAll(People* p);
public:
    People() {
        m_House = "别墅";
        m_Car = "跑车";
    }
public:
    string     m_House;
private:
    string     m_Car;
};

void PeopleFriend::visitAll(People* p) {
    cout << "好朋友访问了你的" << p->m_House << endl;
    cout << "好朋友访问了你的" << p->m_Car << endl;

}
void PeopleFriend::visitPub(People* p) {
    cout << "好朋友访问了你的" << p->m_House << endl;
    //cout << "好朋友访问了你的" << p->m_Car << endl;//不可访问
}

int main() {
    People p;
    PeopleFriend pf;
    pf.visitAll(&p);
    pf.visitPub(&p);

    return 0;
}

4、运算符重载

4.1概念

参考网址:C++语法------详解运算符重载_c++运算符重载-CSDN博客

cpp 复制代码
#include <iostream>
#include <string> //是一个类

using namespace std;

/*
+
4 + 5 = 9

class A {
};

A a;
A b;
a + b;

*/
int main() {
    // 1、加法运算符
    int a = 520;
    int b = 1314;
    cout << a + b << endl;

    // 2、字符串拼接
    string c = "520";
    string d = "1314";
    cout << c + d << endl;//5201314  运算符重载

    string e = "我";
    string f = "爱你";
    cout << e + f << endl;
    return 0;
}

4.2 +号重载

重载形式:[返回值] operator[运算符] (参数...) { ... };

cpp 复制代码
#include <iostream>
using namespace std;

/*
+
*/
// 复数类
class Complex {
    friend Complex operator+(Complex& a, Complex& b);
    friend Complex operator-(Complex& a, Complex& b);
public:
    Complex() : real(0), image(0) {

    }
    Complex(int real, int image) {
        this->real = real;
        this->image = image;
    }
    
    //复数相加函数
    Complex add(Complex& other) { 
        Complex ret;
        ret.real = this->real + other.real;//this 是 指针  other 是 对象
        ret.image = this->image + other.image;
        return ret;
    }

    成员函数重载
    //Complex operator+(Complex& other) {
    //    Complex ret;
    //    ret.real = this->real + other.real;
    //    ret.image = this->image + other.image;
    //    return ret;
    //}

    // a + bi
    void Print() {
        cout << real << '+' << image << 'i' << endl;
    }

private:
    int   real;//实部
    int   image;//虚部
};

//全局函数重载实现  需要两个对象
Complex operator+(Complex& a, Complex& b) {  //引入友元
    Complex ret;
    ret.real = a.real + b.real;
    ret.image = a.image + b.image;
    return ret;
}

Complex operator-(Complex& a, Complex& b) {
    Complex ret;
    ret.real = a.real - b.real;
    ret.image = a.image - b.image;
    return ret;
}

int main() {
    Complex a(10, 20);
    Complex b(5, 8);
    Complex c =a.add(b);
    c.Print();//15+28i
    //Complex c = a.operator+(b);//15+28i
    //Complex c1 = a + b;//函数名变成operator+实现  可以直接实现 成员函数
    
    //全局函数
    Complex c1 = a + b;
    Complex d = a - b;
    c1.Print();
    d.Print();//5+12i
    return 0;
}

4.3 左移重载

cpp 复制代码
#include <iostream>
using namespace std;

/*
左移运算符 :<<  把对象输出来

Complex c;
cout.operator<<(c)  实现

// 成员函数重载
c.operator<<(cout)  cout是ostream对象
c << cout   这个不是我们想实现的
*/
// 复数类
class Complex {
    friend Complex operator+(Complex& a, Complex& b);
    friend Complex operator-(Complex& a, Complex& b);
    friend ostream& operator<<(ostream& cout, Complex a);
public:
    Complex() : real(0), image(0) {

    }
    Complex(int real, int image) {
        this->real = real;
        this->image = image;
    }
    /*
    Complex operator+(Complex& other) {
        Complex ret;
        ret.real = this->real + other.real;
        ret.image = this->image + other.image;
        return ret;
    }*/

    // a + bi
    void Print() {
        cout << real << '+' << image << 'i' << endl;
    }

private:
    int   real;
    int   image;
};

Complex operator+(Complex& a, Complex& b) {
    Complex ret;
    ret.real = a.real + b.real;
    ret.image = a.image + b.image;
    return ret;
}

Complex operator-(Complex& a, Complex& b) {
    Complex ret;
    ret.real = a.real - b.real;
    ret.image = a.image - b.image;
    return ret;
}

//cout重载实现
ostream& operator<<(ostream& cout, Complex a) {//&不会调到拷贝构造函数 只有一个cout
    cout << a.real << '+' << a.image << 'i';
    return cout;//要有返回值<< endl才能实现
}

int main() {
    Complex a(10, 20);
    Complex b(5, 8);
    // Complex c = a.operator+(b);
    Complex c = a + b;
    Complex d = a - b;
    //c.Print();
    //d.Print();
    // operator<<(cout, c)
    cout << c << endl << endl;//重载来实现Complex c的输出
    return 0;
}

有delete 任何地方的不能调用cout的拷贝构造函数。

4.4 递增重载

cpp 复制代码
#include <iostream>
using namespace std;

/*
++

前置 ++
后置 ++
*/

class Complex {
    friend ostream& operator<<(ostream& c, const Complex& a);
public:
    Complex() : real(0), image(0) {}
    Complex(int real, int image) { //有参构造函数
        this->real = real;
        this->image = image;
    }

    Complex& operator++() { //前置 ++
        this->real += 1;
        return *this;  //返回Complex&,就可以用cout << ++(++a) << endl;
    }

    Complex operator++(int) { //后置++  加一个占位符 且必须是int 类型 
        Complex c = *this;  //要返回另一个对象 
        this->real += 1;
        return c;
    }

private:
    int  real;
    int image;
};

//复数的输出
ostream& operator<<(ostream& c, const Complex& a) { //c is cout
    c << a.real << '+' << a.image << 'i';
    return c;
}

class A {

};
A func1() {  // 模拟Complex operator++(int)
    return A();
}
void func2(const A& a) { //模拟ostream& operator<<(ostream& c, const Complex& a)

}

int main() {
    int x = 1;
    cout << ++(++x) << endl;//3
    cout << x << endl;//3

    Complex a(10, 10);
    cout << a << endl;//10+10i
    // ++a;
    cout << ++(++a) << endl;//12+10i
   // cout << a << endl;//11+10i  不加引用时 前置生成另一个对象
    cout << a << endl;//12+10i  加引用时

    cout << a++ << endl;//12+10i
    cout << a << endl;//13+10i

    //func2(func1());//不加const错误 非常量引用的初始值必须为左值

    // cout << ((a++)++)++ << endl;不可以这样写
    cout << a << endl;//13+10i

    int b = 5;
    // cout << ((b++)++)++ << endl;不可以这样写
    cout << b << endl;

    return 0;
}

4,5 赋值重载

cpp 复制代码
#include <iostream>
using namespace std;


class Hero {
public:
    Hero() : m_Data(NULL) {}
    Hero(int data) {
        m_Data = new int;//内存申请
        *m_Data = data;
    }
    // 错误:double delete
    ~Hero() {
        if (m_Data) {//感受内存泄露 if 不重载赋值号:会报错
            delete m_Data;//一个内存调用两次delete 不行
            m_Data = NULL;
        }
    }
    //解决
    Hero& operator=(Hero& h) {
        // m_Data = h.m_Data;//double free问题
        if (m_Data) {
            delete m_Data;
            m_Data = NULL;
        }
        // m_Data=NULL执行
        m_Data = new int;
        *m_Data = *h.m_Data;
        return *this;   //h3 = (h2 = h1);实现
    }

    int* m_Data;
};

int main() {
    Hero h1(1);
    Hero h2(2);
   // if 不重载赋值号
  //  h1 = h2;//h2的m_Data会覆盖h1的m_Data ,内存相同 ,内存泄露
    Hero h3(3);

    cout << h1.m_Data << endl;
    cout << h2.m_Data << endl;
    h1 = h2;  // 
    cout << h1.m_Data << endl;
    cout << h2.m_Data << endl;

    h3 = (h2 = h1);
    cout << h1.m_Data << endl;
    cout << h2.m_Data << endl;
    cout << h3.m_Data << endl;

    return 0;
}

4.6 关系运算符重载

cpp 复制代码
#include <iostream>
using namespace std;

class Point {  //点类
public:
    Point(int x, int y) : m_x(x), m_y(y) {
    }

    bool operator==(const Point& other) const {//函数const包含m_x 和 m_y
        return m_x == other.m_x && m_y == other.m_y;
    }

    bool operator<(const Point& other) const {
        int d = m_x * m_x + m_y * m_y;
        int otherd = other.m_x * other.m_x + other.m_y * other.m_y;
        return d < otherd;
    }
    bool operator>(const Point& other) const {
        if (*this == other) {
            return false;
        }
        if (*this < other) {
            return false;
        }
        return true;
    }
private:
    int m_x, m_y;
};

int main() {
    Point a(1, 6);
    Point b(2, 5);

    if (a == b) { //一个类==要重载
        cout << "a 和 b 相等" << endl;
    }
    else if (a < b) {
        cout << "a 比 b 更加接近原点" << endl;
    }
    else if (a > b) {
        cout << "b 比 a 更加接近原点" << endl;//b 比 a 更加接近原点
    }

    return 0;
}

4.7 函数调用运算符重载

cpp 复制代码
#include <iostream>
using namespace std;

// ()
// add()

class AddFunctor {
public:
    AddFunctor() {
        m_acc = 0;
    }
    int operator() (int a, int b) {
        m_acc++;
        return a + b + m_acc;
    }
private:
    int m_acc;
};

int Add(int a, int b) {
    return a + b;
}

int main() {
    AddFunctor add;//对象
    cout << add(5, 6) << endl;//仿函数  
    cout << add(5, 6) << endl;
    cout << add(5, 6) << endl; 
    cout << add(5, 6) << endl;
    cout << add(5, 6) << endl;

    cout << Add(5, 6) << endl;//每次调用一样
    cout << Add(5, 6) << endl;
    cout << Add(5, 6) << endl;
    cout << Add(5, 6) << endl;
    cout << Add(5, 6) << endl;

    //12 13 14 15 16  11 11 11 11 11
    return 0;
}

5、继承

5.1 继承的语法

cpp 复制代码
#include <iostream>
using namespace std;

/*
*       动物
*      /    \
*    猫      狗
*
* 继承的语法
* class 子类 : 继承方式 父类 {}
* 子类 -> 派生类
* 父类 -> 基类
*/

class Animal {
public:
    void eat() {
        cout << "吃" << endl;  //猫,狗都吃,所以抽象在一个类
    }
};

class Cat : public Animal {
public:
    void sayHi() {
        cout << "喵~" << endl;
    }
};

class Dog : public Animal {
public:
    void sayHi() {
        cout << "汪汪汪~" << endl;
    }
};

int main() {
    Cat c;
    Dog d;
    c.eat();
    d.eat();

    c.sayHi();
    d.sayHi();

    return 0;
}

5.2 继承的方式

cpp 复制代码
#include <iostream>
using namespace std;

/*
继承方式

class 子类名 : 继承方式 父类名 {};

公共 public
保护 protected
私有 private

3 x 3 = 9
                父类权限
             |    public     |     protected      |   private
子类继承方式
  public     |    public     |     protected      |   无法访问
  protected  |   protected   |     protected      |   无法访问
  private    |    private    |      private       |   无法访问

public:   类内可以访问,类外也可以访问
protected:  类内可以访问,类外不可访问,且子类可以访问
private:    类内可以访问,类外不可访问,且子类不可访问
*/

class Animal {
public:
    int m_pub;
protected:
    int m_pro;
private:
    int m_pri;
};

class Cat : public Animal {
public:
    Cat() {
        m_pub = 1;
        m_pro = 2;
        // m_pri = 3; 父类私有成员,子类公有继承,无法访问
    }
};

class BossCat : public Cat {
public:
    BossCat() {
        m_pub = 1;
        m_pro = 2;    // 父类Cat中不是私有
    }
};

void testCat() {
    Cat c;
    c.m_pub = 1;
    // c.m_pro = 2;   // 要么是私有,要么是保护
}

//2
class Dog : protected Animal {
public:
    Dog() {
        m_pub = 1;
        m_pro = 2;
        // m_pri = 3; // 父类私有成员,子类保护继承,无法访问
    }
};

class PoliceDog : public Dog {
public:
    PoliceDog() {
        m_pub = 1;    // 这个变量,在父类 Dog 中一定不是私有成员
        m_pro = 2;    // 这个变量,在父类 Dog 中一定不是私有成员
    }
};

void testDog() {
    Dog d;
    // d.m_pub = 1;   // 要么是保护,要么是私有
    // d.m_pro = 2;   // 要么是保护,要么是私有
}

//3
class Pig : private Animal {
public:
    Pig() {
        m_pub = 1;
        m_pro = 2;
        // m_pri = 3;   // 父类私有成员,子类私有继承,无法访问
    }
};

class WildPig : public Pig {
public:
    WildPig() {
        // m_pub = 1;   // 该变量在父类 Pig 中是私有的
        // m_pro = 2;   // 该变量在父类 Pig 中是私有的
    }
};

void testPig() {
    Pig p;
    // p.m_pub = 1;     // 要么是保护,要么是私有
    // p.m_pro = 2;     // 要么是保护,要么是私有
}

int main() {


    return 0;
}

5.3 构造函数和析构函数顺序

cpp 复制代码
#include <iostream>
using namespace std;

/*
继承中,构造链里,先构造的后析构

d -> c -> b -> a  d继承a..

a b c d d c b a
*/

class Animal {
public:
    Animal() {
        cout << "Animal 构造" << endl;
    }
    ~Animal() {
        cout << "Animal 析构" << endl;
    }
};

class Cat : public Animal {
public:
    Cat() {
        cout << "Cat 构造" << endl;
    }
    ~Cat() {
        cout << "Cat 析构" << endl;
    }
};

class BossCat : public Cat {
public:
    BossCat() {
        cout << "BossCat 构造" << endl;
    }
    ~BossCat() {
        cout << "BossCat 析构" << endl;
    }
};

void Test() {
     //Animal a;
     //Cat c;//先调父类的构造,再调自己
    BossCat b;
}


int main() {
    Test();
    return 0;
}

5.4 同名属性的访问

cpp 复制代码
#include <iostream>
using namespace std;

//父类和子类变量名相同
class Animal {
public:
    Animal() {
        m_Data = 17891;
    }
    int m_Data;
};

class Cat : public Animal {
public:
    Cat() {
        m_Data = 29812;
    }
    int m_Data;
};

void Test() {
    Cat c;
    cout << c.m_Data << endl;//29812
    cout << c.Animal::m_Data << endl;//17891

    cout << &(c.m_Data) << endl;//0000003C3011F92C
    cout << &(c.Animal::m_Data) << endl;//0000003C3011F928  不会覆盖
}

int main() {

    Test();
    return 0;
}

5.5 同名函数访问

cpp 复制代码
#include <iostream>
using namespace std;

class Animal {
public:
    Animal() {

    }
    void eat() {
        cout << "动物吃东西" << endl;
    }
};

class Cat : public Animal {
public:
    Cat() {

    }
    void eat() {
       // Animal::eat();//第一种
        cout << "猫吃东西" << endl;
    }
};


int main() {
    Cat c;
    c.eat();//子类覆盖父类
    //c.Animal::eat();//第二种

    return 0;
}

5.6 多继承

cpp 复制代码
#include <iostream>
using namespace std;

class BaseA {
public:
    int m_A;
    int m_Base;

    BaseA() : m_A(0), m_Base(520) {}//初始化
};

class BaseB {
public:
    int m_B;
    int m_Base;

    BaseB() : m_B(0), m_Base(1314) {}
};

class BaseC {
public:
    int m_C;

    BaseC() : m_C(0) {}
};

class Son : public BaseA, public BaseB, public BaseC {

};

int main() {
    Son s;
    s.m_A = 1;
    s.m_B = 2;
    s.m_C = 3;
    //s.m_Base = 8;//错误:不明确
    s.BaseA::m_Base = 8;
    s.BaseB::m_Base = 9;
    cout << &s.BaseA::m_Base << endl;//存在不同地址
    cout << &s.BaseB::m_Base << endl;
    cout << sizeof(s) << endl;//20 5个整型

    return 0;
}

6、多态

6.1 多态的语法

cpp 复制代码
#include <iostream>
using namespace std;

/*
静态多态:函数重载,运算符重载
动态多态:派生类和虚函数实现运行时的多态
*/

class Animal {
public:
    // 虚函数
    virtual void eat() {
        cout << "动物在吃东西" << endl;
    }
};

class Cat : public Animal {
public:
    void eat() {
        cout << "猫在吃东西" << endl;
    }
};

class Pig : public Animal {
public:
    void eat() {
        cout << "猪在吃东西" << endl;
    }
};


// main -> test -> eat -> Animal::eat
// 函数传参是个动物,但是传入不同的动物,会产生不同的行为,这就叫多态
void eat(Animal& a) {
    a.eat();
}

void Test() {
    Cat c;
    Pig p;
    eat(c);//不加virtual,调用Animal的eat()
    eat(p);//加了  eat()猪在吃东西
}

int main() {
    Test();
    return 0;
}

6.2 虚函数

cpp 复制代码
#include <iostream>
using namespace std;

class Animal {
public:
    virtual void eat() {
        cout << "动物在吃东西" << endl;
    }
    virtual void run() {
        cout << "动物在跑" << endl;
    }
};

class Cat : public Animal {
public:
    void eat() {
        cout << "猫在吃东西" << endl;
    }
};

void eat(Animal& a) {
    Animal b;
    a.eat();
}

void Test() {
    Cat c;
    eat(c);
    cout << "Animal's size = " << sizeof(Animal) << endl;//不加virtual =1  加了=8->指针大小
}


int main() {
    Test();
    return 0;
}

6.3 纯虚函数和抽象类

cpp 复制代码
#include <iostream>

using namespace std;

class Animal { //有纯虚函数 是抽象类 无法实例化
public:
    virtual void eat() = 0;//纯虚函数,在子类实现
};

class Cat : public Animal {
public:
    virtual void eat() {
        cout << "猫在吃东西" << endl;
    }
};

int main() {
    Cat c;
    c.eat();

    return 0;
}

6.4 虚析构和纯虚析构

cpp 复制代码
#include <iostream>
using namespace std;

class BaseA {
public:
    BaseA() {}
    ~BaseA() {
        cout << "BaseA 销毁了" << endl;
    }
};

class SonA : public BaseA {
public:
    SonA() : m_Value(NULL) {
        m_Value = new int(10);//初始化 为10
    }
    ~SonA() {
        cout << "SonA 销毁了" << endl;
        delete m_Value;
    }
    int* m_Value;
};


class BaseB {
public:
    BaseB() {}
    /*virtual ~BaseB() {
        cout << "BaseB 销毁了" << endl;
    }*/
    virtual ~BaseB() = 0;//纯虚析构
};

BaseB::~BaseB() {
    cout << "BaseB 销毁了" << endl;
}

class SonB : public BaseB {
public:
    SonB() : m_Value(NULL) {
        m_Value = new int(10);
    }
    ~SonB() {
        cout << "SonB 销毁了" << endl;
        delete m_Value;
    }
    int* m_Value;
};

int main() {
    BaseA* a = new SonA();
    delete a;

    BaseB* b = new SonB();
    delete b;

    // BaseB x; 抽象类无法进行实例化

    return 0;
}
相关推荐
IT猿手2 小时前
2025最新群智能优化算法:山羊优化算法(Goat Optimization Algorithm, GOA)求解23个经典函数测试集,MATLAB
人工智能·python·算法·数学建模·matlab·智能优化算法
夏天的味道٥3 小时前
使用 Java 执行 SQL 语句和存储过程
java·开发语言·sql
IT、木易4 小时前
大白话JavaScript实现一个函数,将字符串中的每个单词首字母大写。
开发语言·前端·javascript·ecmascript
Mr.NickJJ5 小时前
JavaScript系列06-深入理解 JavaScript 事件系统:从原生事件到 React 合成事件
开发语言·javascript·react.js
Dream it possible!5 小时前
LeetCode 热题 100_字符串解码(71_394_中等_C++)(栈)
c++·算法·leetcode
Archer1946 小时前
C语言——链表
c语言·开发语言·链表
My Li.6 小时前
c++的介绍
开发语言·c++
功德+n6 小时前
Maven 使用指南:基础 + 进阶 + 高级用法
java·开发语言·maven
修己xj6 小时前
算法系列之深度优先搜索寻找妖怪和尚过河问题的所有方式
算法
达斯维达的大眼睛6 小时前
qt小项目,简单的音乐播放器
开发语言·qt