《C++大学教程》 第10章 后续内容 笔记更一下。附部分课后题代码。
当运算符函数作为成员函数实现时,最左边(或者只有最左边)的操作数必须时包含运算符类的一个类对象(或者是对该类对象的一个引用)。
如果左操作数必须是一个不同类的对象或者是一个基本类型对象,那么该运算符函数必须作为非成员函数来实现。
如果非成员运算符函数必须直接访问类的private
或protected
成员,那么该函数可以指定为该类的友元函数。
非成员函数来重载运算符的另一个原因:使运算符具有可交换性。即类的对象不必非得出现在运算符的左侧。
程序员可以使用cast强制类型转换运算符在基本类型之间进行强制转换。
编译器预先并不知道在用户自定义的类型之间、用户自定义类型和基本类型之间如何进行转换,因此程序员必须详细说明该怎么做。
这样的转换可以用构造函数实现,它们是一种将其他类型(包括基本类型)的对象转换成特定类的对象的单参数构造函数。
转换运算符也称为强制类型转换运算符,可用于将某一类的对象转换成另一个类的对象。这种转换运算符必须是非static成员函数。
下列函数原型
MyClass::operator char *() const;
声明了一个重载的强制类型转换运算符函数,可以把用户自定义类型MyClass
的对象转换成一个临时的char *
对象。这个运算符函数声明为const
,因为它并不修改原始的对象。重载的强制类型转换运算符函数不指定返回类型,因为返回类型就是对象正要转换成的目标类型。
如果s
是某个类的对象,当编译器遇到表达式static_cast
时,它会产生函数调用:
s.operator char *()
把操作数转换成char *
。
MyClass::operator int() const;
MyClass::operator OtherClass() const;
声明了两个重载的强制类型转换运算符函数,分别将用户自定义类型MyClass
的对象转换成整数和用户自定义类型OtherClass
的对象。
强制类型转换运算符和转换构造函数的优点之一就是:必要时,编译器可以隐式地调用这些函数来创建临时的对象。
例如,如果用户自定义地String
类的对象s
出现在程序中一个本该出现普通的char *
数据的位置上,如下所示:
cout << s;
那么编译器便可以调用重载的强制类型转换运算符函数operator char *
将对象s
转换成char *
,并在表达式中使用这个转换结果char *
。
如果为我们的String
类提供这个强制类型转换运算符,那么就不必重载流插入运算符便可以使用cout
输出String
对象了。
当隐式转换中使用转换构造函数或者转换运算符时,C++只能应用其中的一个(例如单个用户定义的转换)来尝试满足另一个重载运算符的需要。编译器并不会尝试一系列的用户定义的隐式转换来满足重载运算符的需要。
任何单参数的构造函数都可以被编译器用来执行隐式转换,即构造函数接收的类型会转换成定义了该构造函数的类的对象。
任何单参数且不被声明为explicit
的构造函数可以被编译器用来进行隐式转换,除了拷贝构造函数。
程序员不必使用强制类型转换运算符进行这种转换,它是自动进行的。但是,在某些情况下,隐式转换是不受欢迎的,或者说这种转换很可能会导致错误。
为了允许隐式转换,我们移除了Array
类中的explicit
关键字。
class Array
{
friend std::ostream &operator<<( std::ostream &, const Array & );
friend std::istream &operator>>( std::istream &, Array & );
public:
Array( int = 10 ); // default constructor
Array( const Array & ); // copy constructor
~Array(); // destructor
... ...
};
// Fig. 10.12: fig10_12.cpp
// Single-argument constructors and implicit conversions.
#include
#include "Array.h"
using namespace std;
void outputArray( const Array & ); // prototype
int main()
{
Array integers1( 7 ); // 7-element Array
outputArray( integers1 ); // output Array integers1
outputArray( 3 ); // convert 3 to an Array and output Array抯 contents
} // end main
// print Array contents
void outputArray( const Array &arrayToOutput )
{
cout << "The Array received has " << arrayToOutput.getSize()
<< " elements. The contents are:\n" << arrayToOutput << endl;
} // end outputArray
第13行调用函数outputArray
,以整数值3
作为其实参。可是,这个程序并没有提供一个接收int
参数的名为outputArray
的函数。因此,编译器确定Array
类是否提供了能把int
转换成Array
的转换构造函数。
将参数3
转换成包含了3个元素的临时Array
对象。然后,编译器把这个临时Array
对象传递给函数outputArray
,输出它的内容。
声明每个单参数的构造函数时前面加关键字explicit
,其目的是禁止不应该允许的由转换构造函数完成的隐式转换。即声明为explicit
的构造函数不能再隐式转换中使用。
使用explicit
构造函数创建一个包含3个元素的临时Array
对象,并将它传递给outputArray
函数:
outputArray( Array(3) );
重载函数调用运算符十分重要,因为函数能接受任意数量的逗号分隔参数。
例如,在自定义的String
类中,你能重载该运算符来选择一个String
的子类——两个整型作为参数的运算符能指明开始位置和选择的字串的长度。该operator
函数能检查诸如起始位置超界或者负长度这样的错误。
重载的函数调用运算符必须是一个非静态的成员函数而且可以被以下方式定义:
String String::operator()(size_t index, size_t length) const
假设string1
是一个包含字符串"AEIOU"
的String
对象。当编译器遇到表达式string(2,3)
时,会生成如下的一个成员函数调用:
String1.operator()(2,3)
该调用返回"IOU"
字符串。
另一个关于函数调用运算符可能的应用是启用备用数组下标符号。可能更应该重载函数调用运算符以启用符号chessBoard(row, column)
,其中chessBoard
是一个修改的二维Array
类的对象。
参考本章图10.3、图10.4、图10.10、图10.11。
注意输入格式为英文下的括号和逗号:(real,imaginary)
!
// Fig. 10.14: Complex.h
// Complex class definition.
#ifndef COMPLEX_H
#define COMPLEX_H
class Complex
{
friend std::ostream &operator<<(std::ostream &, const Complex &);
friend std::istream &operator>>(std::istream &, Complex &);
public:
explicit Complex( double = 0.0, double = 0.0 ); // constructor
Complex operator+( const Complex & ) const; // addition
Complex operator-( const Complex & ) const; // subtraction
Complex operator*(const Complex &) const;
bool operator==(const Complex &) const;
bool operator!=(const Complex &right) const
{
return !(*this == right);
}
private:
double real; // real part
double imaginary; // imaginary part
}; // end class Complex
#endif
// Fig. 10.15: Complex.cpp
// Complex class member-function definitions.
#include
#include "Complex.h" // Complex class definition
using namespace std;
// Constructor
Complex::Complex( double realPart, double imaginaryPart )
: real( realPart ),
imaginary( imaginaryPart )
{
// empty body
} // end Complex constructor
// addition operator
Complex Complex::operator+( const Complex &operand2 ) const
{
return Complex( real + operand2.real,
imaginary + operand2.imaginary );
} // end function operator+
// subtraction operator
Complex Complex::operator-( const Complex &operand2 ) const
{
return Complex( real - operand2.real,
imaginary - operand2.imaginary );
} // end function operator-
Complex Complex::operator*(const Complex &operand2) const
{
return Complex(real * operand2.real - imaginary * operand2.imaginary,
real * operand2.imaginary + imaginary * operand2.real);
}
bool Complex::operator==(const Complex &operand2) const
{
if (this->real == operand2.real && this->imaginary == operand2.imaginary)
return true;
else
return false;
}
ostream &operator<<(ostream &output, const Complex &number)
{
output << "(" << number.real << "," << number.imaginary << ")";
return output;
}
istream &operator>>(istream &input, Complex &number)
{
input.ignore();
input >> number.real;
input.ignore();
input >> number.imaginary;
input.ignore();
return input;
}
// Fig. 10.16: fig10_16.cpp
// Complex class test program.
#include
#include "Complex.h"
using namespace std;
int main()
{
Complex x;
Complex y( 4.3, 8.2 );
Complex z( 3.3, 1.1 );
cout << "The default value of x is: ";
cout << x << endl;
cout << "Enter x in the form (1,1): ";
// x.print();
cin >> x;
cout << "\nx: ";
cout << x << endl;
cout << "y: ";
cout << y << endl;
cout << "\nz: ";
cout << z << endl;
x = y + z;
cout << "\n\nx = y + z:" << endl;
cout << x << endl;
cout << " = ";
cout << y << endl;
cout << " + ";
cout << z << endl;
x = y - z;
cout << "\n\nx = y - z:" << endl;
cout << x << endl;
cout << " = ";
cout << y << endl;
cout << " - ";
cout << z << endl;
x = y * z;
cout << "\n\nx = y * z:" << endl;
cout << x << endl;
cout << " = ";
cout << y << endl;
cout << " * ";
cout << z << endl;
Complex a(1, 1);
Complex b(1, 1);
Complex c(2, 2);
cout << "a: ";
cout << a << endl;
cout << "b: ";
cout << b << endl;
cout << "c: ";
cout << c << endl;
if (a == b)
{
cout << "\na and b are equal\n" << endl;
}
else
cout << "a and b are not equal\n" << endl;
if (a == c)
{
cout << "a and c are equal\n" << endl;
}
else
cout << "a and c are not equal\n" << endl;
} // end main
10.11 Polynomial类写到一半突然发现自己理解地太简单了,就放弃了。
第10章已全部更完。
重载这一章看的稀里糊涂。
下周看继承。
没有效率的一周。
个人水平有限,有问题欢迎各位大神批评指正!
部分课后题代码可见:C++大学教程第五版课后答案(第10、11章)