7_静态成员函数_运算符重载_临时对象
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.静态成员函数不属于某个对象,只是属于一个类,也不能被this调用
三目运算符 ? :不能重载
. 也不能重载
= -> [] () (类型转换) 这些运算符只能用成员函数来重载
()是个函数对象,必须是成员
#include
using namespace std;
class F{
int n;
int d;
void reduce(){
int mcd=maxcd(n<0?-n:n,d)
if (mcd!=1) n/=mdc,d/=mcd;
}
public:
F(int n=0,int d=1):n(n),d(d)
{
if(d==0) throw "分母不能为0";
if(d<0) this->d=-d,F::n=-n;
reduce();
cout<<"F("<
/* 静态成员函数 */
static int maxcd(int a,int b) //求最大公约数
{
if(a==0) return b;
return maxcd(b%a,a);
}
friend ostream& operator<<()
{
o<
return o;
}
/*加号运算符重载*/
friend F operator+(const F& lh,const F& rh)
{
/*匿名对象*/
return F (lh.n*rh.d+lh.d*rh.n,lh.d*rh.d);
}
F operator*(const F& rh)const //重载时,成员比友元少一个形参,成员里当前对象作 为第一个操作数
{
/*匿名对象*/
return F (n*rh.n,d*rh.d);
}
friend F operator~(const F& f)
{
return F(f.d,f.n);
}
bool operator!()const;
};
bool F::operator!()const
{
return (n==0); //或者return !n;
}
int main()
{
F f1; //输出0/1
F f2(3); //3传递给第一个参数,结果是3/1
F f3(6,12); //结果是6/12
F f4(4,12);
cout<
return 0;
}
常量和临时值必须要用const
2.临时对象
如果对象变量只用到一次,就直接用匿名对象,编译器可以对匿名对象进行优化,减少对象的创建 ,提高效率。
如果可能尽量使用临时对象。临时对象会及时释放
关于匿名对象的例子:
class Teacher
{
string name;
string course;
public:
Teacher(const char* n,const char* c):name(n),course(c)
{
cout<<"创建"<
Teacher(const Teacher& t):name(),course(t.course)
{
cout<<"复制"<
~Teacher()
{
cout<<"辞退"<
};
int main()
{
Teacher t1("陈宗权","C++");
Teacher t2=t1; //初始化
Teacher t3=Teacher("杨强","UC"); //匿名对象,先创建一个对象,然后复制给t3
//用临时对象来初始化一个新对象,编译器一般会优 化成直接用创建临时对象的参数来创建新对象
t2=t3; //赋值
cout<<"================="<
cout<<"====================="<
}
结果是:
创建陈宗权老师
复制
陈宗权
创建UC老师杨强
===================
创建咨询老师徐微微
辞退咨询老师徐微微
====================
辞退UC老师杨强
辞退咨询老师徐微微
辞退陈宗权
3.例子
struct date{
int year;
int month;
int day;
};
struct Person{
string name;
int age;
bool age;
double salary;
date birth;
Person(){cout<<"创建Person对象在"<
};
class atuoptr{
Person* p;
static int cnt;
public:
autoptr(Person* p):p(p) { ++cnt; }
autoptr(const autoptr& a):p(a.p) { ++cnt; }
~autoptr() {cout<
/*重载->运算符*/
Person* operator->(){return p} //访问谁的成员,就返回谁的地址
/*重载星号运算符*/
Person& operator*(return *p)
};
int autoptr::cnt=0; //静态数据成员在外面初始化
int main()
{
Person* a=new Person; //不会自动调用析构函数
autoptr a=new Person; //自动调用了析构
autoptr b=a; //t==2
autoptr c=a; //t==3
cout<
cout<<(*a).name<
}
4.单例模式
typedef string T;
class Stack{
typedef unsigned int uint;
T* men;
uint max;
uint len;
public:
Stack(uint n):men(new T[n]),max(n),len(0){}
/*拷贝构造函数*/
Stack(const Stack& s):men(new T[s.max]),max(s.max),len(s.len) {}
uint max_size()const
{ return max; }
uint size()const
{ return len; }
Stack& push(const T& e)
{
if(len>=max)
throw 1;
men[len++]=e;
return *this;
}
T pop()
{
if(len==0)
throw 0;
return men[--len];
}
void print()const
{
for(uint i=0;i
~Stack()
{
delete[] men;
}
/*等号运算符的重载 */
Stack& operator=(const Stack& rh)
{
if(this=&rh)
return *this; //可以自己给自己赋值
delete[] men;
men=new T[rh.max];
len=rh.len;
max=rh.max;
for(uint i=0;i
return *this;
}
};
int main()
{
Stack s1(5);
Stack s2(s1);
Stack s2(8);
s1.push("1");
s1.push("2").push("3").push("4");
s2.push("杨强").push("芙蓉");
s1.print();
s2.print();
s3=s2; //s3.operator=(s2)
s1.print();
s2.print();
s3.print();
return 0;
}
什么时候重载=运算符?
什么时候重载默认拷贝构造函数?
重写析构函数,不然后导致重复释放同一块内存。
在有指针成员指向动态内存时,一般要把重载等号运算符,重载默认拷贝构造函数,析构函数这 三大函数重写。
当默认的等号运算符不能满足需要时
拷贝对象时对象里有指针,所以要自己去重载默认
的拷贝构造函数
后++可以重载
前++重载时,要多一个int参数,参数一般默认为0
例子: 强制类型转换重载函数
class F
{
int n;
int d;
public:
F(int n=0,int d=1):n(n),d(d) { }
friend ostream& operator<<(ostream& o,const F& f)
{
o<
}
F& operator++() { n+=d; return *this }
F operator++(int) { F old(*this);n+=d;return old; }
friend F& operator--(F& f){ f.d-=f.d;return f; }
friend F operator--(F& f,int){ F old(f); f.n-=f.d; return old; }
operator double() //类型转换运算符返回类型可以省略
{
return 1.0*n/d;
}
operator bool()
{ return n!=0; }
};
void func1(F a) { cout<
int main()
{
F f1(2,5),f2(4,9),f3(17,3);
cout<<++f1<
cout<
}
例子:重载[] ()
#include
class A
{
public:
typedef unsigned int uint;
private:
int* p;
uint n;
public:
A(uint n):n(n)
{
p=new int[n];
if(p==NULL)
throw 0;
menset(p,0,n*4);
}
~A() { delete[] p; }
uint size()const {return n;}
int& operator[](uint i)const //重载[]运算符
{
return p[i];
if(i>=n)
throw 1;
}
int& operator[](const char* c)const
{
int i=atoi(c);
if(i<0||i>=n)
throw 1;
return p[i];
}
void operator()(int v)
{
for(uint i=0;i
}
void operator()(const char*s)
{
int v=atoi(s);
for(uint i=0;i
}
int operator()(int beg,int delta)
{
for(uint i=0;i
return p[n-1];
}
};
ostream& operator<<(ostream& o,const A& a)
{
o<<"{";
for(int i=0;i
return o;
}
int main()
{
A x(5),y(8);
x[2]=20; //x.operator[](2);
y[6]=66;
cout<<"x="<
y["2"]=33;
cout<<"x="<
cout<<"x="<
y("50"); //函数对象
cout<<"y="<
重载new运算符
delete真正执行是在析构函数之后
class A
{
A(){ cout<<"A()"<
static void* operator new(size_t bytes)
{ cout<<"new A"<<<
{ cout<<"delete A"<
/*重载[],以便于使用new数组*/
static void* operator new[](size_t bytes)
{ cout<<"new[] A"<
是7,4个字节是保存元素个数的变量
static void operator delete[](void*p)
{ cout<<"delete[] A"<
};
int main()
{
A* x=new A; //先分配空间,然后自动执行构造函数
delete x; //执行析构,然后执行delete释放空间
x=new A[3];
delete[] x;
}
new和delete不管是否重载,默认都是static,属于类的
不管什么类型的变量至少占用一个字节!
如果要new一个数组,必须重载[],否则不会被调用new和delete
new一个数组的时候会额外占用4个字节来保存元素的个数