一、自增自减运算符
单目运算符:正号(+) 负号(-) ++ --
开始代码:
#include <iostream>
using namespace std;
class point
{
private:
int x;
int y ;
public:
int getX(){ return x;}
void setX(int x) { this->x = x;}
int gety(){ return y;}
void sety(int y) { this->y = y;}
public:
point(int x = 0 ,int y = 0);
point operator=(const point& other);
point operator+=(const point& other);
int operator[](int x);
void operator()(int a,int b);
// 前加加
// point operator++();
//后加加
// point operator++(int);
};
point::point(int x,int y)
:x(x),y(y)
{
}
全局函数实现方式(前++): student operator++(const stduent& other);
成员函数实现方式(前++):point point::operator++();
//前加加运算符
point operator++(point& other)
{
other.setX(other.getX()+1);
other.sety(other.gety()+1);
return other;
}
//前++(成员函数)
point point::operator++()
{
this->x++;
this->y++;
return *this;
}*
全局函数实现方式(后++): student operator++(const stduent& other,int);
成员函数实现方式(后++):point point::operator++(int );
全局函数:
//后加加运算符
point operator++(point& other,int)
{
point temp = other;
other.setX(other.getX()+1);
other.sety(other.gety()+1);
return temp;
}
//后加加实现(成员函数)
point point::operator++(int)
{
point temp = *this;
this->x++;
this->y++;
return temp;
}
注意:默认情况下,加加运算符是前加加,也就是++danny;
二、赋值运算符
格式1: void operator=(const person& other);
格式2: void operator+=(const person& ohter);
案例: 赋值运算符可以连续使用
//赋值运算符
point point::operator=(const point& other)
{
this->x = other.x;
this->y = other.y;
return *this;
}
主函数的说明:
point* px = new point(14,14);
++(*px);
cout << "px->x"<< px->getX()<<endl;
point ptemp = (*px)++; //拷贝构造
point danny(1,2);
ptemp = (*px); //赋值运算符 x=y=z;
cout << "px->x"<< ptemp.getX()<<endl;
danny = ptemp = (*px);
cout << "danny.x" << danny.getX()<<endl;
注意:赋值运算符只可以是成员函数实现方式,不可以是全局函数和友元函数
如果没有手动添加赋值运算符,编译器会自动添加缺省赋值运算符。
三、下标运算符
格式: int operator[](int x)
案例:
//下标运算符
int point::operator[](int x)
{
if(x >= 2 || x < 0) { return y; }
else if( x == 1) { return y; }
else { return x; }
}
主函数调用:
cout << "px->x"<< ptemp.getX()<<endl;
danny = ptemp = (*px);
cout << "danny.x" << danny.getX()<<endl;
cout << "danny[1]" << danny[1] <<endl;
注意:只可以是成员函数实现
四.流运算符
定义:在使用cout或者cin的时候,会用到<< 和 >>运算符,这就是流运算符
对象: cout是输出对象,已经定义好的,是ostream类型对象
cin是输入对象,已经定义好的,是istream的类型对象
格式1: ostream& operator<<(ostream& out,student& other); 输出流
格式2: istream& operator>>(istream& in,point& other) 输入流
注意: 只可以是全局函数实现流操作符,不可以是成员函数和友元函数
案例:
ostream& operator<<(ostream& out,point& other)
{
out << "x="<<other.getX()<<" y = "<<other.gety()<<endl;
return out;
}
istream& operator>>(istream& in,point& other)
{
int x=0;
int y=0;
in>>x>>y;
other.setX(x);
other.sety(y);
return in;
}
五、小括号运算符
定义:函数调用运算符重载,有时候希望对象有像函数一样的使用方式,
也称之为仿函数,没有固定的写法,比较灵活;
格式: 返回值 operator()(参数){}
调用: 对象(参数);
案例:
//函数调用运算符 括号运算符
void point::operator()(int a,int b)
{
cout << "a ="<<a << "b =" << b <<endl;
}
调用:danny(1,2); ----以这种方式进行调用
六、继承
1.为什么要继承
面向对象啊设计中非常重要的概念是继承,继承允许使用另外一个类来定义新类
达到了代码重用的作用和提高执行效率
提高了开发效率,不需要重新写父类有的成员函数和方法。
1)概念
父类:也叫基类,例如动物类派生出基类,动物类是基类,
子类:也叫派生类,例如动物类派生出鸡类,鸡类是子类;
关系: 基类是已经有的类,派生类是继承了父类产生的新类
2)格式: class 子类: 继承控制 父类{ };
3)继承控制: public private protected三种,使用最多的是public
public继承:父类中的共有成员,子类继承后还是公有
父类中的私有成员,子类继承后不可以使用;等价于没继承
父类中的保护成员,子类继承后还是保护成员;
private继承:将父类的属性在子类中修改成私有,父类私有子类无法访问;
protected继承:将父类的属性在子类中修改成保护,父类私有子类无法访问;
4)子类无法继承
A: 父类的构造函数,析构函数,拷贝构造没法继承
B: 父类的友元函数和友元类没法继承
C: 父类中的重载的运算符没法继承
5)继承的构造顺序
A: 先构造父类,再构造子类,父类的构造在子类的构造函数初始化列表中调用;
B: 先析构子类对象,再析构父类对象;
C:所有的子类在初始化列表中都会调用父类的构造函数;
如果子类构造没有主动添加父类构造,编译器自动调用父类的缺省构造函数;
D: 子类复制了所有父类的成员变量和方法,父子类之间是不同的内存空间;
E: 如果子类定义了父类的相同方法或变量,则隐藏了父类的方法和变量,优先使用子类
七、多继承
1.定义: 一个子类继承了多个父类,具有多个父类的方法和属性
2.格式:class 子类:public 父类1 , public 父类2{};
3)多继承中构造函数和析构函数顺序
构造顺序:父类是先继承先构造,后继承后构造,构造完父类后构造子类
例如: class pandan:public cat,public bear
上例子中:先构造cat,再构造bear ,然后构造pandan
析构顺序:先析构子类,再调用后继承的类,再析构先继承的类
例如: class pandan:public cat,public bear
上例子:先析构pandan,再析构 bear 再析构cat (入栈和出栈的过程)
3.菱形继承(需要避免)
一个父类产生两个子类,然后两个子类继续产生孙子类,在孙子类中有多个爷爷变量
(虚继承解决菱形继承的问题)
八、内部类和局部类
1.内部类:定义在类中的类;
如果将类A定义在类B中,那么A是B的内部类(类嵌套)
2.特点
内部类支持public private protected属性限制;
内部类中的成员函数可以直接访问外部类的所有成员函数(反过来不行)
内部类可以访问static的成员变量
内部类不会影响外部类的内存;
内部类可以在外部类中申明,在外部实现(申明和实现可以分开)
3.局部类:定义在函数内部的类;
4.局部类的特点:
作用域在函数内部,只可以在函数内部使用,在外部没法定义对象
所有的成员必须定义在类的内部,不允许定义static变量
局部类不可以访问函数中的局部变量;
5.匿名对象
定义:没有变量名,没有被指针指向的对象,用完后立马调用析构释放;
匿名对象使用不会和引用关联;
Class Box{ public: Box(int x = 0){} } ; Box fun() { return Box(1); }
6.构造函数相互调用
为什么用: 构造函数可以有参数,使得代码量大,可在构造中调用自己的其他构造;
考虑长期问题,代码修改的内容比较小,一个构造修改,其他全部修改;
实现方式:在子类的构造函数初始化列表中调用父类的构造函数;