头图

复习

0.1 构造函数

对象被创建的时候,会自动调用
全局对象
局部对象
堆中的对象
构造函数的函数名字和类名一样
构造函数没有返回值,可以有参数,可以重载,一个类中可以实现多个构造函数

0.2 析构函数

对象被销毁的时候,会自动调用
全局对象 程序结束的时候会自动销毁
局部对象 离开作用域的时候,会自动销毁
堆中的对象 delete释放的时候,会自动销毁
析构函数名字:~ 类名
析构没有返回值,没有参数,不能重载,一个类就只能有1个

0.3 拷贝构造函数

一个对象初始化另外一个对象的时候,会自动调用

class  CTest
{
//......
    private:
int m_nNum;
}
1. 直接初始化
int  main()
{
     CTest  obj1;
     CTest obj2 = obj1;
}
2. 函数传参的时候
void  Fun(CTest obj)
{

}
Fun(obj1);

编译器默认会提供一个浅拷贝的拷贝构造。
当类中成员,有指针指向堆空间的时候,我们大概率需要自己实现一个深拷贝的拷贝构造

0.4 转换构造函数

只有一个参数的构造函数,也称之为转换构造函数。
这个语法容易造成误解,可以使用explicit 禁止转换

1. 继承

1.1 继承的基本语法

#include <iostream>
class CA
{
public:
    CA() :m_a(1)
    {

    }
    void Fun1()
    {
        std::cout << m_a;
    }
public:
    int m_a;
};
//继承的语法:
//class 子类:public 父类的名字
class CB:public CA
{
public:
    CB() :m_b(2)
    {

    }
    void Fun2()
    {
        std::cout << m_b;
    }
public:
    int m_b;
};
int main()
{
    std::cout << sizeof(CB)<<std::endl;
    CB objB;
    objB.Fun1();//这个函数从CA继承而来
    objB.Fun2();//自己实现的

    objB.m_a = 100;//使用的从CA继承来的
    objB.m_b = 200;//自己定义的

    return 0;
}

图片.png

1.3 继承的权限

子类包含父类中的所有成员
子类也可以使用父类中的成员
在使用类的成员的时候,有两种情况:
1.通过类对象,在类外使用成员变量和成员函数
2.在类内的函数中,直接使用成员变量和成员函数
图片.png

#include <iostream>
class CBase
{
public:
    int m_BaseA;
    void FunCBase()
    {
        std::cout << "我是CBase的FunCBase" << std::endl;
    }
protected:
    int m_BaseB;
private:
    int m_BaseC;
};
class CA :public CBase
{
public:
    void FunCA()
    {
        m_BaseA = 10;
        m_BaseB = 20;
        //m_BaseC = 5; 父类中的私有成员,无论如何继承都不能直接访问
    }
};
class CB :protected CBase
{
public:
    void FunCB()
    {
        m_BaseA = 10;
        m_BaseB = 20;
        //m_BaseC = 5; 父类中的私有成员,无论如何继承都不能直接访问
    }
};
class CC :private CBase
{
public:
    void FunCC()
    {
        m_BaseA = 10;
        m_BaseB = 20;
        //m_BaseC = 5; 父类中的私有成员,无论如何继承都不能直接访问
    }
};
class CTest1 :public CB
{
public:
    void FunTest1()
    {
        m_BaseA = 10;
        m_BaseB = 20;
    }
};
class CTest2 :public CC
{
public:
    void FunTest2()
    {
        //m_BaseA = 10;
        //m_BaseB = 20;
    }
};

int main()
{
    CA objA;
    CB objB;
    CC objC;
    //CA是公有继承,公有继承也称之为  【接口继承】
    //父类中是公有的,在子类中还是公有的,接口依然是接口
    objA.m_BaseA = 1;
    objA.FunCBase();
    //私有继承或者保护结成也称之为  【实现继承】
    //会使得父类中的公有成员变为私有的或者保护的
    //子类就失去了父类中的接口,变成了内部实现。
    //objB.m_BaseA = 2;
    //objB.FunCBase();
    //objC.m_BaseA = 2;
    //objC.FunCBase();

    //保护继承和私有继承,都是实现继承,有什么区别呢???
    //私有继承,原公有或者保护成员,
    //在子类中都变成了私有成员,再往下继承,就会不可访问
    //保护继承,原公有或者保护成员,
    //在子类中都是保护属性,再往下继承,类内还是能访问的

    return 0;
}

1.4 重定义问题

父类中和子类中,只要重名了,就会发生重定义。通过子类对象访问同名成员,默认访问的都是子类自己的。父类中的同名成员被隐藏了。
无论是函数名和函数名同名,还是变量名和变量名同名,还是变量名和函数名同名。函数名同名,无论参数是一样还是不一样,都是重定义。父类中的标识符,都会隐藏,默认使用子类自己的。
注意:父类和子类中同名函数,不能构成重载的,因为他们作用域不同

#include <iostream>
class CBase
{
public:
    void Fun()
    {
        std::cout << "CBase的Fun" << std::endl;
    }
    void Fun1()
    {

    }
    int m_BaseA;
};
class CA :public CBase
{
public:
    void Fun1(int n)
    {

    }
    int m_BaseA;
    int Fun;
};
int main()
{
    CA obj;
    obj.Fun = 100;
    obj.Fun();
    obj.Fun1();
    obj.m_BaseA = 10;
    return 0;
}

1.5 在继承关系中构造析构调用问题

#include <iostream>
class CTest1 
{
public:
    CTest1(int n) :m_Test1(n)
    {
        std::cout << "我是Test1成员构造" << std::endl;
    }
    ~CTest1() 
    {
        std::cout << "我是Test1成员析构" << std::endl;
    }
public:
    int m_Test1;
};
class CTest2
{
public:
    CTest2(int m) :m_Test2(m)
    {
        std::cout << "我是Test2成员构造" << std::endl;
    }
    ~CTest2()
    {
        std::cout << "我是Test2成员析构" << std::endl;
    }
public:
    int m_Test2;
};
class CBase1
{
public:
    CBase1(int n) :m_BaseA(n)
    {
        std::cout << "我是1父类构造" << std::endl;
    }
    ~CBase1()
    {
        std::cout << "我是1父类析构" << std::endl;
    }
    int m_BaseA;
};
class CBase2
{
public:
    CBase2(int m) :m_BaseA(m)
    {
        std::cout << "我是2父类构造" << std::endl;
    }
    ~CBase2()
    {
        std::cout << "我是2父类析构" << std::endl;
    }
    int m_BaseA;
};
class CA :public CBase1,public CBase2
{
public:
    CA() : obj2(20),m_A(2), obj1(10), CBase2(6), CBase1(5)
    {
        std::cout << "我是子类构造" << std::endl;
    }
    ~CA()
    {
        std::cout << "我是子类析构" << std::endl;
    }
    CTest1 obj1;
    CTest2 obj2;
    int m_A;
};
int main()
{
    CA obj;
    return 0;
}

总结:
1.构造优先调用父类,再调用成员,最后调用自己
2.析构顺序和构造顺序相反
3.父类构造需要传参,就在子类的初始化列表中主动调用父类的构造传参
4.成员的构造需要传参,也需要在类的初始化列表中主动调用成员的构造传参
5.成员的构造顺序和定义顺序一致
6.父类的构造顺序和继承顺序一致

1.6 多继承的问题

#include <iostream>
class CBase1
{
public:
    CBase1(int n) :m_Base1(n)
    {
        std::cout << "我是1父类构造" << std::endl;
    }
    ~CBase1()
    {
        std::cout << "我是1父类析构" << std::endl;
    }
    int m_Base1;
};
class CBase2
{
public:
    CBase2(int m) :m_Base2(m)
    {
        std::cout << "我是2父类构造" << std::endl;
    }
    ~CBase2()
    {
        std::cout << "我是2父类析构" << std::endl;
    }
    int m_Base2;
};
class CA :public CBase1, public CBase2
{
public:
    CA() :  m_A(2),  CBase2(6), CBase1(5)
    {
        std::cout << "我是子类构造" << std::endl;
    }
    ~CA()
    {
        std::cout << "我是子类析构" << std::endl;
    }
public:
    int m_A;
};
int main()
{
    //子类多继承的时候,和单继承差不多的,拥有所有父类的所有成员
    CA obj;
    obj.m_Base1 = 10; //从CBase1继承来的
    obj.m_Base2 = 20; //从CBase2继承来的
    obj.m_A = 30;     //这个是它自己的
    return 0;
}

具体示例:

#include <iostream>
class Cpeople
{
public:
    void Run()
    {
        std::cout << "我在快乐的跑步" << std::endl;
    }
public:
    char m_szName[20];
    int m_nGender;
    int nAge;
};
class CSpider//蜘蛛
{
public:
    void Tusi()
    {
        std::cout << "Piu" << std::endl;
    }
public:
    int nAge;
};
class CSuperHero
{
public:
    void SaveWorld()
    {
        std::cout << "拯救世界" << std::endl;
    }
    int nAge;
};
class CSPiderMan :public Cpeople, public CSpider,public CSuperHero
{
public:
    void BianShen()
    {
        std::cout << "Piu" << std::endl;
    }
};
int main()
{
    CSuperHero obj1;
    obj1.SaveWorld();
    CSPiderMan obj;
    obj.Run();
    obj.Tusi();
    obj.BianShen();
    obj.SaveWorld();

    //注意多继承的时候,多个父类如果有同名成员,会造成二义性问题。
    //可以使用作用域防止BUG产生
    //更好的方式是使用虚继承
    obj.CSpider::nAge = 5;
    obj.Cpeople::nAge = 20;
    obj.CSuperHero::nAge = 15;
    return 0;
}

2. 命名空间

命名空间机制是为了防止命名冲突
math1.h

#pragma once
namespace Code1
{
    int GetMax(int a, int b);

    int GetAdd(int a, int b);
}

math1.cpp

namespace Code1
{
    int GetMax(int a, int b)
    {
        if (a > b)
        {
            return a;
        }
        else
        {
            return b;
        }
    }
    int GetAdd(int a, int b)
    {
        return a + b;
    }
}

math2.h

#pragma once
namespace Code2
{
    int GetMax(int a, int b);
    int GetAvg(int a, int b);
    namespace inner
    {
        int GetMin(int a, int b);
    }
}

math2.cpp

namespace Code2
{
    int GetMax(int a, int b)
    {
        if (a < b)
        {
            return b;
        }
        else
        {
            return a;
        }
    }
}
namespace Code2
{
    int GetAvg(int a, int b)
    {
        return (a + b) / 2;
    }
    namespace inner
    {
        int GetMin(int a, int b)
        {
            if (a < b)
            {
                return a;
            }
            else
            {
                return b;
            }
        }
    }

}

主文件

#include "Math1.h"
#include "Math2.h"
using Code1::GetMax;
using Code2::GetAvg;
namespace mi = Code2::inner;
int main()
{

    GetMax(10, 20);
    GetAvg(10, 15);
    mi::GetMin(5, 10);
    return 0;
}

补充作业:
1.设计一个狼人类,继承自人类和狼类。
a.人类:学习方法 有年龄属性 有参构造进行初始化
b.狼类:攻击方法 有奔跑速度属性 有参构造进行初始化
c.狼人类:变身方法 有攻击力属性 有参构造进行初始化
定义正确定义狼人对象,能够调用继承过来的所有函数

#include<iostream>
using namespace std;
class people
{
public:
    people(int age) :m_age(age) //构造函数使用
    {

    }
    void study()
    {
        cout << "i am study now" << endl;          //学习方法
    }
private:
    int m_age;
};
class wolf
{
public:
    wolf(int speed) :m_speed(speed)    //构造函数使用
    {

    }
    void attack()
    {
        cout << "i am fighting here" << endl;
    }
private :
    int m_speed;
};
class wolfman :public people, public wolf  //多继承,继承多个成员的属性
{
public:
    wolfman(int power,int age, int speed):power(power),people(age),wolf(speed)//构造函数,用于初始化成员
    {

    }
    void bianshen()
    {
        cout << "update!" << endl;
    }
private:
    int power;  //初始化新定义的power
};
int main()
{
    wolfman obj(100, 20, 70);
    obj.study();
    obj.attack();
    obj.bianshen();
    return 0;
}

瞿小凯
1.3k 声望593 粉丝