类的结构
c++中使用class定义一个类,类中的数据与函数默认是私有的(private),同时可以将一部分的数据定义为公有的(public),私有部分的数据/函数只能被类中的函数访问,公有部分的内容可以被整个类的作用域访问,公有的成员函数被称为接口,成员函数在类中声明,在类外定义函数体。
以下是一个最简单的类,后续所有操作将在这个类的基础上扩展
#include<ostream>
#include<istream>
using std::osstream;
class sock
{
private:
int a;
int b;
public:
sock(); //构造函数的名称与类名相同
sock(int c, int d);
~sock(); //析构函数
}
sock::sock() //默认构造函数(在自定义构造函数时,必须自己提供默认构造函数)构造函数没有返回值类型
{
}
sock::sock(int c, int d) //自定义构造函数(未定义构造函数的时候将会自动提供一个默认构造函数)
{
a = c;
b = d;
}
sock::~sock()
//析构函数(函数体通常为空)注意析构函数和销毁类的因果关系,在销毁类的时候调用析构函数,而不是调用析构函数导致类被销毁。
{
cout << "ok" << std::endl; //已经在头文件中暴露了ostream
}
void sock::show()
{
cout << a << std::endl;
cout << b << std::endl;
}
友元函数
类中的函数允许访问私有成员,但是在某些时候需要对接口进行扩展,也需要对类的私有成员进行访问,基于这种思想,在c++中出现了一类函数,函数本身不是类的成员函数,但是可以直接访问类的私有对象。
友元函数需要通过在函数前加friend定义,同时友元函数在类中定义
对上面的类进行扩展加入友元函数
#include<ostream>
#include<istream>
using std::osstream;
class sock
{
private:
int a;
int b;
public:
sock(); //构造函数的名称与类名相同
sock(int c, int d);
~sock(); //析构函数
firend void sum(const sock& a);
}
sock::sock() //默认构造函数(在自定义构造函数时,必须自己提供默认构造函数)构造函数没有返回值类型
{
}
sock::sock(int c, int d) //自定义构造函数(未定义构造函数的时候将会自动提供一个默认构造函数)
{
a = c;
b = d;
}
sock::~sock()
//析构函数(函数体通常为空)注意析构函数和销毁类的因果关系,在销毁类的时候调用析构函数,而不是调用析构函数导致类被销毁。
{
cout << "ok" << std::endl; //已经在头文件中暴露了ostream
}
void sock::show()
{
cout << a << std::endl;
cout << b << std::endl;
}
void sum(const sock& a)
{
int sum;
sum=a.a+a.b;
cout<<sum<<endl;
}
成员函数和友元函数的异同
相同点:
成员函数和非成员函数都需要在类中定义,同时都可以访问这个类的私有对象。
不同点:
在类外定义函数体时成员需要使用域名运算符进行定义
成员函数使用时由类运算符(.)调用,友元函数直接使用
成员函数实际上隐式调用了当前类(即含有this指针),友元函数没有这个功能
#include<ostream>
#include<istream>
using std::osstream;
class sock
{
private:
int a;
int b;
public:
sock(); //构造函数的名称与类名相同
sock(int c, int d);
~sock(); //析构函数
firend void sum(const sock& a);
}
sock::sock() //默认构造函数(在自定义构造函数时,必须自己提供默认构造函数)构造函数没有返回值类型
{
}
sock::sock(int c, int d) //自定义构造函数(未定义构造函数的时候将会自动提供一个默认构造函数)
{
a = c; //这里实际上可以理解为this->a=c;,即隐式调用当前对象
b = d;
}
sock::~sock()
//析构函数(函数体通常为空)注意析构函数和销毁类的因果关系,在销毁类的时候调用析构函数,而不是调用析构函数导致类被销毁。
{
cout << "ok" << std::endl; //已经在头文件中暴露了ostream
}
void sock::show()
{
cout << a << std::endl;
cout << b << std::endl;
}
void sum(const sock& a)
{
int sum;
sum=a.a+a.b; //友元函数必须显示的使用对象
cout<<sum<<endl;
}
运算符重载与友元函数
运算符重载
c++中
多态的一种,及运算符的多态
运算符多态的核心在于重新对运算符定义,给予运算符不同的含含义,使用运算符重载来代替一部分函数。
重载运算符使用operate定义
#include<ostream>
#include<istream>
using std::osstream;
class sock
{
private:
int a;
int b;
public:
sock(); //构造函数的名称与类名相同
sock(int c, int d);
~sock(); //析构函数
firend void sum(const sock& a);
sock operate+(const sock& a);
friend sock operate+(const sock& a,const sock& b);
}
sock::sock() //默认构造函数(在自定义构造函数时,必须自己提供默认构造函数)构造函数没有返回值类型
{
}
sock::sock(int c, int d) //自定义构造函数(未定义构造函数的时候将会自动提供一个默认构造函数)
{
a = c; //这里实际上可以理解为this->a=c;,即隐式调用当前对象
b = d;
}
sock::~sock()
//析构函数(函数体通常为空)注意析构函数和销毁类的因果关系,在销毁类的时候调用析构函数,而不是调用析构函数导致类被销毁。
{
cout << "ok" << std::endl; //已经在头文件中暴露了ostream
}
void sock::show()
{
cout << a << std::endl;
cout << b << std::endl;
}
void sum(const sock& a) //友元函数
{
int sum;
sum=a.a+a.b; //友元函数必须显示的使用对象
cout<<sum<<endl;
}
sock sock::operate+(sock& a) //运算符重载算成员函数
{
sock c;
c.a=a+a.a;
c.b=b+a.b;
return c;
}
sock sock::operate+(sock& a,sock& b) //运算符重载友元函数
{
sock c;
c.a=b.a+a.a;
c.b=b.b+a.b;
return c;
}
在使用成员函数作为重载函数时我们在使用过程中看如下代码
int main()
{
sock a=(1,2);
sock b=(2,3);
sock c;
c=a+b; //在这里实际上可以理解为a.operate+(b),即a作为左值,b作为参数表传入
}
在加法中大部分时候这两张没有很大的区别,但是对于某些运算符号将会出现一些问题
<<运算符的重载
#include<ostream>
#include<istream>
using std::ostream;
class sock
{
private:
int a;
int b;
public:
sock(); //构造函数的名称与类名相同
sock(int c, int d);
~sock(); //析构函数
firend void sum(const sock& a);
sock operate<<(ostream& a);
friend sock operate+(const sock& a,ostream os);
}
sock::sock() //默认构造函数(在自定义构造函数时,必须自己提供默认构造函数)构造函数没有返回值类型
{
}
sock::sock(int c, int d) //自定义构造函数(未定义构造函数的时候将会自动提供一个默认构造函数)
{
a = c; //这里实际上可以理解为this->a=c;,即隐式调用当前对象
b = d;
}
sock::~sock()
//析构函数(函数体通常为空)注意析构函数和销毁类的因果关系,在销毁类的时候调用析构函数,而不是调用析构函数导致类被销毁。
{
cout << "ok" << std::endl; //已经在头文件中暴露了ostream
}
void sock::show()
{
cout << a << std::endl;
cout << b << std::endl;
}
void sum(const sock& a) //友元函数
{
int sum;
sum=a.a+a.b; //友元函数必须显示的使用对象
cout<<sum<<endl;
}
void operator<<(sock& s, std::ostream& os) //友元函数重载
{
os << s.a << std::endl << s.b;
}
void operator<<(std::ostream& os) //成员函数重载
{
os << a << std::endl << b;
}
注意使用成员函数和友元函数在<<重载的区别
注意在使用中的区别
int main()
{
sock a=(1,2);
a<<std::cout; //由于成员函数相当于a.operate<<(std::ostream os)
cout<<a; //友元函数定义的(习惯性写法)
}
即友元函数可以直接使用交换律等(但是这里要注意一个很重要的事情如下程序展示)
int operator+(int a,char b); //函数一
int operator+(char b,int a); //函数二
/*这两个 函数在c++中被认为是不一样的*/
//看下面两个加法式
int a;
char b;
int c;
c=a+b; //调用函数一
c=b+a; //调用函数二
//即以上说明了只有友元函数才能实现交换率,同时要实现交换率要同时创建两个运算符重载函数。