const修饰成员函数的几种情况:
1.const 在函数的最后,表示该成员函数不具有更改对象成员变量的权限;
class Stack
{
public:
void Push(int elem);
int Pop(void);
int GetCount(void) const; // const 成员函数
private:
int m_num;
int m_data[100];
};
int Stack::GetCount(void) const
{
++m_num; // 编译错误,企图修改数据成员m_num
Pop(); // 编译错误,企图调用非const 函数,
return m_num;
}
2.const放在函数返回值的前面的时候,是修饰返回值不能被修改,即函数的返回给的数据也必须是const的;
例如函数:
const char * GetString(void);
如下语句将出现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();
需要说明的是:只要函数不修改对象的成员变量,就应该在函数定义之后加上const,这样的话,该函数既可以被const对象也可以被非const对象调用;
const对象只能调用const函数,而非const对象既可以调用const函数,也可以调用非const函数,在const函数中只能调用其他的const函数,即使被调用的函数不修改成员变量,const函数也不允许去调用非const函数
友元函数:
友元函数是一种打破对象的封装的函数,用friend关键字声明,而与声明的位置无关(无论在public还是private中都是一样的),友元函数的权限是被扩大,可以通过向友元函数传递对象来修改对象中的成员变量,
void ModfityA(myclass &a)
{
a.a = 100;//正常来说,该函数是不具有修改a中成员变量的权限的,因为a是一个private的成员,但是在类的声明中一旦将该函数声明成类的友元函数,这句话将
//会被允许
}
在类中声明友元函数的格式:
class myclass
{
public:
friend void ModfityA(myclass &a);//在类中将函数声明成为友元函数,则该函数具有修改对象中成员变量的权限,声明位置无关
private:
int a;
int b;
}
友元类:
像友元函数一样可以在类中任何位置声明;被声明为友元类的B可以随便的访问A中的私有成员变量,但是friend的方向是单向的,你是我的友元类,但是我不一定是你的友元类;
当类A将类B声明为友元函数的时候,B中的对象都具有访问A中的私有变量的权限
class myclass
{
public:
friend class myclass1;//此处将myclass1类声明为这个类的友元类,
private:
int a;
int b;
}
class myclass1
{
public:
void GetA(const myclass &a)//类myclass1中就可以访问A类对象的私有成员变量
{
cout << a.a << endl;
}
};
运算符重载:
C++允许对操作符进行重载,操作符本质上可以看成是函数名称,,针对于类对象的操作的定义叫做运算符的重载,
重载的格式:
类型 类名::operator op(参数列表)
例如:friend myclass operator + (myclass C1,myclass C2);
两种实现方式:
class Complex
{
public:
private:
int a;
int b;//实部和虚部
}
针对于以上的类,在实现复数的加法运算的时候可以采用下列两种方式中的一种:
1.通过友元函数来实现:
通过在类中加入一个友元函数:
在类中的任何位置声明friend Complex operator +(const Complex&C1,Complex C2);
Complex operator +(const Complex& C1,Complex C2)
2.通过成员函数来实现:
由于成员函数本身是具有this指针的访问权的,所以运算符的参数会少一个;
Complex Complex::operator +(const Complex& C2);
而在调用该重载的操作符的时候:
可以使用诸如C3=C1+C2;
运算符重载的一些注意:
一些可以重载和不能重载的操作符:
同时不能更改运算符的优先级,结合性,操作数,不能创造新的操作符;
一元操作符的重载例子:
前置++ 的实现:
1.成员函数法:
class myclass
{
public:
myclass& operator ++()//通过成员函数实现前置++
{
this->a++;
this->b++;
return *this;
}
private:
int a;
int b;
}
2.友元函数法:
class myclass
{
public:
friend myclass operator ++(myclass & C1)//通过友元函数实现前置++
{
C1.a++;
C1.b++;
return C1;
}
private:
int a;
int b;
}
后置++ 的实现:
1.成员函数法:
class myclass
{
public:
myclass operator ++(int)//通过成员函数实现后置++
{
myclass tmp(*this);
this->a++;
this->b++;
return tmp;
}
private:
int a;
int b;
}
2.友元函数实现:
class myclass
{
public:
friend myclass operator ++(myclass & C1,int)//通过友元函数实现后置++,与前置++ 参数列表上不同在于一个占位参数
{
myclass tmp(C1);
C1.a++;
C1.b++;
return tmp;
}
private:
int a;
int b;
}
对于输入输出流左移和右移运算符的重载:
由于左移和右移操作符的用在输入和输出的时候是属于iostream类对象中的重载的,所以如果想通过成员函数的方法使地<<和>>得到重载是不可能的,因此只能通过友元函数的方法来实现成重载:
重载<<
friend ostream& operator<<(ostream& out, const myclass& C)
{
out << C.a << C.b << endl;
return out;
}
对于等号=的重载:
由于C++编译器默认是会提供给一个类似与浅拷贝的=赋值操作符,所以对于=的重载一般都是对含有指针的成员变量的更改:
错误存在的分析:简单的复制使得两个对象中的指针指向同一块内存中,这样在释放内存的时候会发生错误;
因此含有指针成员变量的=重载基本步骤是:
1.将旧指针的内容释放,2.根据新对象的长度申请新的内存空间3.完成对新的内存空间的拷贝
格式是:
myclass& operator=(const myclass& C)
{
delete this->p;
this->p = new char[10];
for (int i = 0;i < 10;i++)
{
this->p[i] = C.p[i];
}
return C;//由于需要等号的连续赋值,在这里返回this指针和C对象是一样的
}