C++核心 DAY3
友元
类中三种权限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;
}总之就是继承的多份数据变成了一份数据