返回值问题
int &Array::operator[] ( int subscript )
{
assert( 0 <= subscript && subscript < size );
return ptr[ subscript ];
}
const int &Array::operator[]( int subscript ) const
{
assert( 0 <= subscript && subscript < size );
return ptr[ subscript ];
}
为什么这两个成员函数一个返回左值一个返回右值?
[解决办法]
返回的如果是非const的引用的话,它就是一个对象的别名,是个左值,可以取地址和修改它的内容。但是如果是const 的引用的话,它就是一个不开改动的值,可以参考我所写的一个验证性的程序:
//本程序研究怎样进行对函数返回值操作而不影响实参,以及怎样让对函数返回值的操作影响到实参的值
//以及怎么禁止对函数返回值进行操作的几种方法。
,
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
inline int &max1(int a,int b)
{
return a <b? b:a;
}
inline int &max2(int &a ,int &b)
{
return a <b? b:a;
}
inline int &max3(const int &a,const int &b)
{
return a <b? b:a;
}
inline int * max4(int *a ,int *b)
{
return *a <*b? b:a;
}
inline const int * max5(int *a , int *b)
{
return *a <*b? b:a;
}
inline const int &max6(int &a ,int &b)
{
return a <b? b:a;
}
void main()
{
int a=1,b=2,c=3,d=4;
int *p1=&a,*p2=&b,*p3=&c,*p4=&d;
cout < < "a,b调用函数++max1前a= " < <a < < "\tb= " < <b < <endl;
cout < < "++max1(a,b)本身的值为 " < <++max1(a,b) < <endl;
cout < < "a,b调用函数++max1后a= " < <a < < "\tb= " < <b < <endl;
//对次函数max1的调用结果说明当参数传递为传值时,即使返回的是指针和引用,对返回值的操作也不会影响到
//原来的参数
cout < < "a,b调用函数++max2前a= " < <a < < "\tb= " < <b < <endl;
cout < < "++max2(a,b)本身的值为 " < <++max2(a,b) < <endl;
cout < < "a,b调用函数++max2后a= " < <a < < "\tb= " < <b < <endl;
//对此函数max2的调用结果说明当参数和返回值都是引用的时候,对返回值的操作将改变实参的值
cout < < "c,d调用函数++max3前c= " < <c < < "\td= " < <d < <endl;
cout < < "++max3(c,d)本身的值为 " < <++max3(c,d) < <endl;
cout < < "c,d调用函数++max3后c= " < <c < < "\td= " < <d < <endl;
//原来以为将max3的两个形参声明为const的引用,即使返回的是引用,对返回值的操作就不能改变实参
//但是结果确实改变了实参d的值,猜测原因就是对实参是引用的限制只在实参的那个作用域里面有效,也就是
//说只在函数体和那个实参列表中是const的引用,当函数返回以后对返回值操作不受const的限制了。因为对
//引用的说明就是在参数里声明的。
cout < < "p1,p2调用函数++(*max4(p1,p2))前a= " < <*p1 < < "\tb= " < <*p2 < <endl;
cout < < "++(*max4(p1,p2))本身的值为 " < <++(*max4(p1,p2)) < <endl;
cout < < "p1,p2调用函数++(*max4(p1,p2))后a= " < <*p1 < < "\tb= " < <*p2 < <endl;
//本段程序说明当参数和返回值都是指针的时候,对返回值的操作将改变实参的值
/*
cout < < "p1,p2调用函数++(*max5(p1,p2))前a= " < <*p1 < < "\tb= " < <*p2 < <endl;
cout < < "++(*max5(p1,p2))本身的值为 " < <++(*max5(p1,p2)) < <endl;
cout < < "p1,p2调用函数++(*max5(p1,p2))后a= " < <*p1 < < "\tb= " < <*p2 < <endl;
*/
//上面这段程序不能通过编译,因为*max5(p1,p2)返回的是一个const 指针,不能被修改。
/* cout < < "a,b调用函数++max6前a= " < <a < < "\tb= " < <b < <endl;
cout < < "++max6(a,b)本身的值为 " < <++max6(a,b) < <endl;
cout < < "a,b调用函数++max6后a= " < <a < < "\tb= " < <b < <endl;
*/
//上面的这段程序也不能被编译,因为max6(a,b)返回的是一个const引用,不能被修改。
}
/*总结:(1)本程序使用了inline函数,以前都一直以为inline只可以用做类的成员函数
(2)通过本函数验证了只有在一种情况下对函数返回值的操作会影响到实参
1。参数是引用或指针(这个引用和指针可以是const的),返回值是引用或指针(这个引用或指针绝对
不能为const的),要同时满足这两个条件才可以。
(3)要避免对返回值的操作影响到实参,只要避免(2)的两个条件即可,尤其有效的是将返回值声明为
const的时候,这样任何试图对返回值的操作都将导致编译失败。如果既要对返回值进行操作,又要
操作结果不影响实参,可以使用传值的方式。
*/
[解决办法]
函数重载同函数的参数列表和cv-qualifier有关。只要这两者中任何一个不同,则视为重载,否则非法。
所以,不要试图仅仅通过返回值重载一个函数,这是非法的。
[解决办法]
参量类型的差异
重载函数之间的区别在于带有不同初始值的参量类型。因而对一个给定类型的参量以及对于该类型的引用,在重载的意义上来说是完全相同的。它们被看成是相同的,因为它们采用了相同的初始值。例如:max(double,double)和(double&,double &)是完全相同的,说明两个这样的函数会引起错误。
出于相同的原因,用修饰符const和volatile进行修饰的函数参量类型同基本类型,在重载的意义上看没有什么不同。
然而重载函数的机制可以区分由const或volatile修饰的引用以及基本类型的引用。这使得可以有下列代码:
#include <iostream.h>
class Over
{
public:
Over() {cout < < "Over default constructor\n "}
Over(over &o){cout < < "Over &\n ";}
Over(const Over &co) {cout < < "const Over &\n ";}
Over(volatile Over &vo) {cout < < "volatile Over &\n ";}
};
void main()
{
Over o1; //调用缺省构造函数
Over o2(o1); //调用Over(Over&)
const Over o3;//调用缺省构造函数
Over o4(o3); //调用Over(const Over &)
volatile Over o5; //调用缺省构造函数
Over o6(o5); //调用Over(volatile Over &)
}
指向const和volatile对象的指针和指向其基本类型的指针在重载意义上是不同的。
重载函数的限制
一组重载函数是否是可接受的如下限制:
* 该组重载函数中任何两个都必须有不同的参量表。
* 具有相同类型参量表、仅在返回值类型上不同的重载函数会引起错误。
Microsoft特殊处
用户可以仅仅基于返回类型不同而重载new运算符。尤其在基于说明的存储器模式修饰符不同时。
Microsoft特殊处结束
* 成员函数的重载不能仅基于一个说明为静态的,另一个说明为非静态的。
* typedef说明并未定义新的类型,它们仅为已存在的类型引入了一个同义词。它们不能影响重载机制。考虑下面的代码:
typedef char * PSTR;
void Print(char * szToPrint);
void Print(PSTR szToPrint);
前面的两个函数有相同的参量表,PSTR是类型char *的同义词。在成员范围中, 这样的代码会产生错误。
* 枚举类型是一些可区分的类型,故可以区分重载函数。
* 从区分重载函数的意义上说,类型“数组”和“指针”是相同的。对于一维数组来说是正确的。因而下面的重载函数出现了冲突,并会产生一条错误消息:
void Print (char * szToPrint);
void Print (char szToPrint[]);
对于多维数组,第二和后续维数视为类型的一部分,因此它们可以用来区分重载函数:
void Print (char szToPrint []);
void Print (char szToPrint [][7]);
void Print (char szToPrint [][9][42]);