友元

类中三种权限public,protected,private,只有Public是在哪里都可以访问,现在有一个private,类外不可访问。如果你想要他可以访问,则需要用到友元

全局函数做友元,类做友元,成员函数做友元

  • 全局函数做友元

这里类似 静态成员变量 static int ,类内声明,类外初始化。 在类内用一个friend +函数声明

class house
{
    friend void goodgay(house *h);
public:
    string a;
    house()
    {
        a="pubilc客厅";
        b="private卧室";
    }
private:
    string b;

};


void goodgay(house *h)
{
    cout<<"好基友正在访问你的"<<h->a<<endl;
    cout<<"好基友正在访问你的"<<h->b<<endl;
}

  • 类做友元

这里很简单就是一个类作为另一个类的友元 之前还有一个类做另一个类的成员 构造时候先构造小的再大的,析构时先大后小

这个案例中 goodgay初始化就是一个house指针,这个new的house指针指向一个初始化好的house,然后goodgay类做友元可以访问house中的private,goodgay这个类中的函数也可以访问到private;

class house;

class goodgay
{
public:
    goodgay();
    void visit();
private:
    house *h;
};
goodgay::goodgay()
{
    h =new house;
}
class house
{
    friend class goodgay;
public:
    house();
    string a;
private:
    string b;
};
house::house()
{
    this->a="public客厅";
    this->b="private卧室";
}



void goodgay::visit()
{
    cout<<"好基友正在访问"<<h->a<<endl;
    cout<<"好基友正在访问"<<h->b<<endl;
}


void test()
{
    goodgay g;
    g.visit();
}
  • 成员函数做友元

只需要改动一行

class house
{
    friend void goodgay::visit2();
public:
    house();
    string a;
private:
    string b;
};

运算符重载

这里的内容其实就是把我们平时常用的运算符+,-,++等重新写成我们需要的。 像内置的数据类型,编译器是知道怎么去运算的,这里重载主要是针对struct和class

加号运算符重载

这里主要用于2个自定义数据类型相加

成员函数重载

class person
{
public:
    person(){};
    person(int a,int b)
    {
        this->m_a=a;this->m_b=b;
    }
    //p3=p1+p2
    person operator+(const person &p)
    {
        person p3(0,0);
        p3.m_a=this->m_a+p.m_a;
        p3.m_b=this->m_b+p.m_b;
        return p3;
    }
    int m_a,m_b;
};


void test()
{
    person p1(10,10);
    person p2(20,20);
    person p3=p1+p2;
    cout<<p3.m_a<<" "<<p3.m_b<<endl;
}

全局函数重载

person operator+(const person&p1,const person&p2)
{
    person p3;
    p3.m_a=p1.m_a+p2.m_a;
    p3.m_b=p1.m_b+p2.m_b;
    return p3;
}

还可以写成这样

Person operator+(const Person& p2, int val)

{

Person temp;

temp.m_A = p2.m_A + val;

temp.m_B = p2.m_B + val;

return temp;

}

左移运算符重载

这里主要是作用与 自定义类型输出

  • ostream流,可以理解为管道,将数据流向指定的地方,这里是将数据流向屏幕输出其他的还有文件,控制台;

  • cout可以是编译器已经内置好的命令,一读到这个语句就知道是要输出东西到屏幕,正常的cout<<"wo",这个语句可以理解为 编译器读到cout,好,计算机现在知道了要输出东西到屏幕上,就是<<之后的东西。

  • 就像运动员听到发令枪之后起跑一样,计算机接收到cout就知道是要将<<之后的内容输出到屏幕上

  • 这里<<运算符重载 记得返回的是ostream&,这是链式编程思想,方便cout<<p1<<"hello world"<<endl;

  • cout+"wo" cout<<"wo"

class person
{
    friend ostream& operator<<(ostream& out,const person &p);
public:
    person(){};
    person(int a,int b)
    {
        this->m_a=a;this->m_b=b;
    }

private:
    int m_a,m_b;
};


ostream& operator<<(ostream& out,const person &p)
{
    out<<"p.a="<<p.m_a<<" p.b="<<p.m_b<<endl;
    return out;
}



void test()
{
    person p1(10,10);
    person p2(20,20);
    cout<<p1<<"hello world"<<endl;
}

递增运算符输出

前置递增

这里接的返回的是myint&,这样是在当前的p上进行修改,方便链式编程,如果返回的是myint,那么返回的只是*this的副本。 副本的v从0编程1,若此时继续++,则是这份副本在++,原本的p只是进行了第一次的++.

class  myint
{
    friend void show(const myint p);
public:
    myint()
    {
        v=0;
    }
    myint& operator++()
    {
        this->v++;
        return *this;
    }
private:
    int v;
};

void show(const myint p)
{
        cout<<p.v<<endl;
}

void test()
{
    myint p;

    show(++(++p));
    show(p);
}

后置递增

int作占位参数?? 我也不知道为什么,可能就是++运算符的规则,如果后面跟着int就是后置++。就像++运算符他只要一个参数就能运行一样,不是a+b,只需要a++;

myint operator++(int)
{
    myint t=*this;
    this->v++;
    return t;
}
void test()
{
    myint p;
    show(p++);
    show(p++);
    show(p);
}

前置可以链式,后置不行,在int类型上也这样

赋值运算符重载

浅拷贝问题

new开辟的内存在堆区要由程序员手动开辟手动释放

析构函数的逻辑是这一串代码跑完的时候,这里是test,自动运行,所以p1的析构完了,p2的析构就出问题了,空间释放了2次

class person
{
public:
    person(int age)
    {
        this->m_age=new int(age);
    }
    ~person()
    {
        if(this->m_age!=NULL)
        {
            delete this->m_age;
            this->m_age=NULL;
        }
    }
    int *m_age;
};
void test()
{
    person p1(10);
    person p2(20);
    p2=p1;
    cout<<"p1的值"<<*p1.m_age<<endl;
    cout<<"p2的值"<<*p2.m_age<<endl;

}

返回person&可解决链式编程问题

class person
{
public:
    person(int age)
    {
        this->m_age=new int(age);
    }
    ~person()
    {
        if(this->m_age!=NULL)
        {
            delete this->m_age;
            this->m_age=NULL;
        }
    }
    person& operator=(const person &p)
    {
        if(m_age!=NULL)
        {
            delete m_age;
            m_age=NULL;
        }
        this->m_age=new int(*p.m_age);
        return *this;
    }
    int *m_age;
};
void test()
{
    person p1(10);
    person p2(20);
    person p3(30);
    p2=p1=p3;
    cout<<"p1的值"<<*p1.m_age<<endl;
    cout<<"p2的值"<<*p2.m_age<<endl;
    cout<<"p3的值"<<*p3.m_age<<endl;
}

关系运算符重载

这里比较简单,主要用于两个自定义对象类型进行比较

class person
{
public:
    person(int age,string name)
    {
        this->name=name;
        this->age=age;
    }
    //判断相等
    bool operator==(const person &p)
    {
        if(p.age== this->age&&p.name== this->name)
        {
            return 1;
        }
        return 0;
    }
    bool operator!=(const person &p)
    {
        if(p.age== this->age&&p.name== this->name)
        {
            return 0;
        }
        return 1;
    }
    string name;
    int age;
};




void test()
{
    person p1(10,"刘帅");
    person p2(20,"刘帅");
    if(p1==p2)
        cout<<"两者相等"<<endl;
    else cout<<"两者不相等"<<endl;
    if(p1!=p2)
        cout<<"两者不相等"<<endl;
    else cout<<"两者相等"<<endl;
}

函数调用运算符重载

函数调用运算符?听起来很奇怪,其实就是()重载

类名不能直接调用对象函数,例如myprint("woshi"),myadd(10,20),这种写法是错误的。因为编译器会认为你i在用myprint新建一个参数为()的对象,当作了构造函数。

class myprint
{
public:
    void operator()(string a)
    {
        cout<<a<<endl;
    }

};
void test01()
{
    myprint a;
    a("HELLO WORLD");
}

class myadd
{
public:
    int operator()(int a,int b)
    {
        return a+b;
    }

};

void test02()
{
    myadd a;
    cout<<a(10,20)<<endl;

}

多态

这个内容比较简单,主要是理解。

记得继承怎么使用的

继承的好处:可以减少重复的代码

class A : public B;

A 类称为子类 或 派生类

B 类称为父类 或 基类

继承方式

这里是前面的权限的作用

继承方式一共有三种:

  • 公共继承

  • 保护继承

  • 私有继承


从这个图看一看到,先不管什么继承方式,先是完完整整的把父类里面所有的成员copy过来了。

如果是公有继承,那么就是照抄父类。 如果是保护继承,那么父类里继承过来的都是保护权限,如果是私有继承,那么父类继承过来的都是私有权限。

保护继承和私有继承都是类内可访问,类外不可以

继承中的对象模型

其实这里是完整的把父类复制了一份下来,黑马C++的课程可以查看到。但是Clion现在不行

class father
{
public:int a;
protected: int b;
private: int c;
};
class son: private father
{
public:
    int age;
};


void test()
{
    cout<<sizeof(father)<<endl;
    cout<<sizeof(son)<<endl;
}

继承中构造和析构顺序

先大的构建,再小的构建,析构相反

记得好像类对象作为类成员 是先小后大,析构相反

class father
{
public:
    father()
    {
        cout<<"father构造函数"<<endl;
    }
    ~father()
    {
        cout<<"father析构函数"<<endl;
    }
};
class son :public father
{
public:
    son()
    {
        cout<<"son构造函数"<<endl;
    }
    ~son()
    {
        cout<<"son析构函数"<<endl;
    }
};


void test()
{
   son a;
}

继承同名成员处理方式

注意访问成员的方式 son.::fatehr

class father
{
public:
    father()
    {
      age=50;
    }
    void show()
    {
        cout<<"正在访问father show函数"<<endl;
    }
    int age;
};
class son :public father
{
public:
    son()
    {
        age=5;
    }
    void show()
    {
        cout<<"正在访问son show函数"<<endl;
    }
    int age;
};


void test()
{
   son s;
   cout<<s.age<<endl;
   cout<<s.father::age<<endl;
   s.show();
   s.father::show();
}

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

访问成员属性

class father
{
public:
    static void show()
    {
        cout<<"正在访问fater 静态show函数"<<endl;
    }
    static void show(int a)
    {
        cout<<"正在访问fater 静态show函数"<<a<<endl;
    }
 static int age;
};
int father::age=50;
class son :public father
{
public:
    static void show()
    {
        cout<<"正在访问son 静态show函数"<<endl;
    }
static int age;
};
int son::age=15;

void test()
{
   //访问成员属性
   son s;
   //1 通过对象访问
   cout<<s.age<<endl;
   cout<<s.father::age<<endl;
   //2直接通过类名访问
   cout<<son::age<<endl;
   cout<<father::age<<endl;
}

访问成员函数

可以看到之前father里面的show函数发生了重载,但是还是无法直接用s.show(10)这种方式访问

出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问

void test1()
{
    //访问成员属性
    son s;
    //1 通过对象访问
    s.show();
    s.father::show();
    //2直接通过类名访问
    son::show();
    father::show();
}

多继承语法

了解下,理解就好,了解使用方式

class base1 :public base2,public base 3
{
}

菱形继承

菱形继承问题可以用虚继承来解决

class Animal

{

public:

	int m_Age;

};

//继承前加virtual关键字后,变为虚继承

//此时公共的父类Animal称为虚基类

class Sheep : virtual public Animal {};

class Tuo   : virtual public Animal {};

class SheepTuo : public Sheep, public Tuo {};

void test01()

{

	SheepTuo st;

	st.Sheep::m_Age = 100;

	st.Tuo::m_Age = 200;

	cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;

	cout << "st.Tuo::m_Age = " <<  st.Tuo::m_Age << endl;

	cout << "st.m_Age = " << st.m_Age << endl;

}

总之就是继承的多份数据变成了一份数据