11-use class

心得:
1、当有类对象s,s1,s2,且有运算符重载函数时

s=s1+s2    等价于   s=s1.operator+(s2)

此处隐式使用s1,而显式使用s2(因其作为函数的参数传递)
这两种方法都将调用operator+()方法。在第一种方法中,运算符左侧的对象是调用对象,运算符右侧的对象是作为参数被传递的对象。

2、将函数参数声明为引用的目的是为了提高效率,如果按值传递类对象,代码的功能是相同的,但传递引用速度将更快,使用的内存将更少。

3、不能重载下面的运算符

1sizeofsizeof运算符。
2).     :成员运算符。
3).*    :成员指针运算符
4)::    :作用域解析运算符
5)?:    :条件运算符。

4、普通四则运算重载

    Vector Vector::operator-(const Vector & b) const
    {
        Vector diff;
        diff.ang = b.ang;
        return diff;
    }

5、友元(友元函数,友元类,友元成员函数)
通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。

通常,在为类重载二元运算符时(带两个参数的运算符)常常需要友元。
例如,将某对象乘以实数时,乘法运算符将一个Time值与一个double值结合,这限制了该运算符的使用方式。因为左侧的操作数是调用对象。也就是说:

A=B*2.75    等价于   A=B.operator*(2.75)

但是,如果A=2.75*B呢?这个式子不对应于成员函数,因为2.75不是Time类型的对象。
于是告诉我们,只能用A=B*2.75的形式编写。

另一种方式是,使用非成员函数Vector operator*(double n, const Vector & a)
但这种常规非成员函数方式存在一个问题,它不能访问类的私有成员。

于是便有了友元
1)利用友元函数,访问私有成员。
步骤1:将其原型放在类声明中,并在其原型声明前加上关键字friend
friend Vector operator*(double n, const Vector & a)
注意:
虽然该函数在类中声明,但它不是成员函数,因此不能使用成员运算符来调用
虽然它不是成员函数,但是跟成员函数的访问权限相同。
步骤2:作函数的定义时,去掉friend关键字,且不需要类作用域运算符
友元函数并非有悖于OOP,应将友元函数看做类扩展接口的组成部分。只有类声明能决定哪个函数是友元
对非成员重载运算符函数,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。

在友元函数的定义中,只能显式地访问类的私有数据成员(a.成员)或者把a作为一个整体,让成员函数来处理私有值,如下。

所以,有下面的两种方式重载*运算符

6、重载<<运算符

ostream & operator<<(ostream & os, const c_name & obj)
{
    os << ....;
    return os;
}

返回一个ostream对象的引用即可。

7、重载运算符:作为成员函数还是非成员函数(友元函数)
V1:成员函数 Vector operator+(const Time & t) const;
对于成员函数,一个操作数通过this指针隐式访地传递,另一个操作数作为函数参数显式传递

V2:友元函数friend Vector operator+(const Time & t1,const Time & t2) const;
对于非成员函数,两个操作数都作为参数来传递。

8、在类声明中声明公有类型的状态成员,这种成员描述的是对象所处的状态
enum mode {A,B};

当友元函数需要使用A和B时,由于友元函数不在类作用域内,于是必须使用类名::A的形式

9、使用构造函数来完成重载运算符

Vector Vector::operator+(const Vector & b) const{
    return Vector(x + b.x, y + b.y);
}

上述代码将新的x和y分量传递给Vector的构造函数,而后者使用这些值来创建无名的新对象并返回该对象的副本。这确保了新的Vector对象是根据构造函数制定的标准规则创建的。

10、对于定义类特定的常量来说,如果它们是整数,enum提供了一种方便的途径
enum {year=12};
当然,还有另外一种办法,static const int year=14;

11、
Stone a;
a=19.6;
程序将使用构造函数Stone(double)来创建一个临时对象,并将19.6作为初始化值。随后采用逐个成员赋值的方式将该临时对象的内容赋值到a中。这一过程为隐式转换,因为它是自动进行的,而不需要显式强制类型转换。

注意:
只有接受一个参数的构造函数才能作为转换函数。
特别地,如果其他的参数提供了默认值,便可用于转换第一个参数的类型。

12、利用explicit关键字来关闭自动转换特性。也就是说,声明构造函数时
explicit Stone(double n);
那么,11中的隐式转换方式将不可用,只允许显示转换
a=Stone(19.6);

13、创建转换函数,要转化为typeName类型,需要下面格式的转换函数
operator typeName( );

注意:
转换函数必须是类方法!因此需要类对象来调用
转换函数不能指定返回类型!因为typeName已经指出了要转换成的类型。
虽然没有声明返回类型,但转换函数也将返回所需的值(私有成员)。
转换函数不能含有参数!类对象调用转换函数告知函数要转换的值,因此不需要参数

例如,声明了成员函数
operator int() const;
则主函数中,可以使用显式强制类型转换 int x=(int) a;

另一种方法是:用一个功能相同的非转换函数(成员函数)来替换转换函数,但仅在被显式调用时,该函数才会执行。即,可以将
Stone::operator int(){return int (p+0.5);}
替换为int Stone::Stone_to_Int(){return int (p+0.5);}
这样,语句int d=a;将是非法的。可以使用int d=a.Stone_to_Int();

猜你喜欢

转载自blog.csdn.net/csdn_dzh/article/details/80003272