目录
1、重载逻辑操作符
1、原生逻辑操作符
逻辑运算符的原生语义
-操作数只有两种值(true和false)
-逻辑表达式不用完全计算就能确定最终值
-最终结果只能是true或者false
编程实验
逻辑表达式 test.cpp
#include <iostream>
#include <string>
using namespace std;
int func(int i)
{
cout << "int func(int i) : i = " << i << endl;
return i;
}
int main()
{
if( func(0) && func(1) )
{
cout << "Result is true!" << endl;
}
else
{
cout << "Result is false!" << endl;
}
cout << endl;
if( func(0) || func(1) )
{
cout << "Result is true!" << endl;
}
else
{
cout << "Result is false!" << endl;
}
return 0;
}
2、重载逻辑操作符
逻辑操作符可以重载吗? 重载逻辑操作符有什么意义?
编程实验
重载逻辑操作符 test.cpp
#include <iostream>
#include <string>
using namespace std;
class Test
{
int mValue;
public:
Test(int v)
{
mValue = v;
}
int value() const
{
return mValue;
}
};
bool operator && (const Test& l, const Test& r)
{
return l.value() && r.value();
}
bool operator || (const Test& l, const Test& r)
{
return l.value() || r.value();
}
Test func(Test i)
{
cout << "Test func(Test i) : i.value() = " << i.value() << endl;
return i;
}
int main()
{
Test t0(0);
Test t1(1);
if( func(t0) && func(t1) ) //operator && (func(0),func(1))
{
cout << "Result is true!" << endl;
}
else
{
cout << "Result is false!" << endl;
}
cout << endl;
if( func(1) || func(0) )
{
cout << "Result is true!" << endl;
}
else
{
cout << "Result is false!" << endl;
}
return 0;
}
在C语言已经知道函数参数调用顺序是不确定的,且目前大多数为从右到左(函数调用约定)
问题的本质分析
① C++通过函数调用扩展操作符的功能
② 进入函数体前必须完成所有参数的计算
③ 函数参数的计算次序是不定的
④ 短路法则完全失效
逻辑操作符重载后无法完全实现原生的语义!!!
一些有用的建议
-实际工程开发中避免重载逻辑操作符
-通过重载比较操作符代替逻辑操作符重载
-直接使用成员函数代替逻辑操作符重载
-使用全局函数对逻辑操作符进行重载
2、重载逗号操作符
1、原生逗号操作符
逗号操作符可以构成逗号表达式
-逗号表达式用于将多个子表达式连接为一个表达式
-逗号表达式的值为最后一个子表达式的值
-逗号表达式中的前N-1个子表达式可以没有返回值
-逗号表达式按照从左向右的顺序计算每个子表达式的值
实例分析
逗号表达式的示例 test.cpp
#include <iostream>
#include <string>
using namespace std;
void func(int i)
{
cout << "func() : i = " << i << endl;
}
int main()
{
int a[3][3] = {
(0, 1, 2),
(3, 4, 5),
(6, 7, 8)
};
int i = 0;
int j = 0;
while( i < 5 )
func(i),
i++;
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
cout << a[i][j] << endl;
}
}
(i, j) = 6;
cout << "i = " << i << endl;
cout << "j = " << j << endl;
return 0;
}
2、重载逗号操作符
在C++中重载逗号操作符是合法的
使用全局函数对逗号操作符进行重载
重载函数的参数必须有—个是类类型
重载函数的返回值类型必须是引用
Class& operator , (const Class& a, const Class& b)
{
return const_cast<Class&>(b);
}
编程实验
重载逗号操作符 test.cpp
#include <iostream>
#include <string>
using namespace std;
class Test
{
int mValue;
public:
Test(int i)
{
mValue = i;
}
int value()
{
return mValue;
}
};
Test& operator , (const Test& a, const Test& b)
{
return const_cast<Test&>(b);
}
Test func(Test& i)
{
cout << "func() : i = " << i.value() << endl;
return i;
}
int main()
{
Test t0(0);
Test t1(1);
Test tt = (func(t0), func(t1)); // operator , (func(t0),func(t1))
cout << tt.value() << endl; // 1
return 0;
}
(不可预期)
搞笑的是当注释操作符重载后
(可预期)
问题的本质分析
① C++通过函数调用扩展操作符的功能
② 进入函数体前必须完成所有参数的计算
③ 函数参数的计算次序是不定的
④ 重载后无法严格从左向右计算表达式
工程中不要重载逗号操作符!!!
3、重载前置++操作符和后置++操作符
1、值得思考的问题
下面的代码有没有区别?为什么?
i++; // i的值作为返回值, i自增1
++i; // i自增1, i的值作为返回值
编程实验
真的有区别吗? test.cpp
int main()
{
int i = 0;
i++;
++i;
return 0;
}
在工程中,编译器会在忽略返回值情况下进行优化,即在工程中它们没有区别!!!
意想不到的事实
-现代编译器产品会对代码进行优化
-优化使得最终的二进制程序更加高效
-优化后的二进制程序丢失了C/C++的原生语义
-不可能从编译后的二进制程序还原C/C++程序
-C/C++开发的软件无法完全反编译!
++操作符可以重载吗? 如何区分前置++和后置++?
2、++操作符重载
++操作符可以被重载
-全局函数和成员函数均可进行重载
-重载前置++操作符不需要额外的参数
-重载后置++操作符需要—个int类型的占位参数
编程实验
++操作符的重载 test.cpp
#include <iostream>
#include <string>
using namespace std;
class Test
{
int mValue;
public:
Test(int i)
{
mValue = i;
}
int value()
{
return mValue;
}
// 重载前置++
Test& operator ++ ()
{
++mValue;
return *this;
}
// 重载后置++
Test operator ++ (int) //引入了第二个对象,效率...
{
Test ret(mValue); //根据C中i++的语义,先返回值,再自加
mValue++;
return ret;
}
};
int main()
{
Test t(0);
Test tt = t++;
cout << tt.value() << endl;
cout << t.value() << endl;
++t;
cout << t.value() << endl;
return 0;
}
对于基础类型的变量
-前置++的效率与后置++的效率基本相同
-根据项目组编码规范进行选择
对于类类型的对象
-前置++的效率高于后置++
-尽量使用前置++操作符提高程序效率
编程实验
复数类的进—步完善 class Complex
Complex.h
#ifndef _COMPLEX_H_
#define _COMPLEX_H_
class Complex
{
double a;
double b;
public:
Complex(double a = 0, double b = 0);
double getA();
double getB();
double getModulus();
Complex operator + (const Complex& c);
Complex operator - (const Complex& c);
Complex operator * (const Complex& c);
Complex operator / (const Complex& c);
bool operator == (const Complex& c);
bool operator != (const Complex& c);
Complex& operator = (const Complex& c);
Complex& operator ++ ();
Complex operator ++ (int);
};
#endif
Complex.cpp
#include "Complex.h"
#include "math.h"
Complex::Complex(double a, double b)
{
this->a = a;
this->b = b;
}
double Complex::getA()
{
return a;
}
double Complex::getB()
{
return b;
}
double Complex::getModulus()
{
return sqrt(a * a + b * b);
}
Complex Complex::operator + (const Complex& c)
{
double na = a + c.a;
double nb = b + c.b;
Complex ret(na, nb);
return ret;
}
Complex Complex::operator - (const Complex& c)
{
double na = a - c.a;
double nb = b - c.b;
Complex ret(na, nb);
return ret;
}
Complex Complex::operator * (const Complex& c)
{
double na = a * c.a - b * c.b;
double nb = a * c.b + b * c.a;
Complex ret(na, nb);
return ret;
}
Complex Complex::operator / (const Complex& c)
{
double cm = c.a * c.a + c.b * c.b;
double na = (a * c.a + b * c.b) / cm;
double nb = (b * c.a - a * c.b) / cm;
Complex ret(na, nb);
return ret;
}
bool Complex::operator == (const Complex& c)
{
return (a == c.a) && (b == c.b);
}
bool Complex::operator != (const Complex& c)
{
return !(*this == c);
}
Complex& Complex::operator = (const Complex& c)
{
if( this != &c )
{
a = c.a;
b = c.b;
}
return *this;
}
Complex& Complex::operator ++ ()
{
a = a + 1;
b = b + 1;
return *this;
}
Complex Complex::operator ++ (int)
{
Complex ret(a, b);
a = a + 1;
b = b + 1;
return ret;
}
main.cpp
#include<iostream>
#include"Complex.h"
using namespace std;
int main()
{
Complex c(1,2);
++c;
cout<<c.getA()<<endl;
cout<<c.getB()<<endl;
c++;
cout<<c.getA()<<endl;
cout<<c.getB()<<endl;
}
4、小结
C++从语法上支持逻辑操作符重载
重载后的逻辑操作符不满足短路法则
工程开发中不要重载逻辑操作符
通过重载比较操作符替换逻辑操作符重载
通过专用成员函数替换逻辑操作符重载
逗号表达式从左向右顺序计算每个子表达式的值
逗号表达式的值为最后—个子表达式的值
操作符重载无法完全实现逗号操作符的原生意义
工程开发中不要重载逗号操作符
编译优化使得最终的可执行程序更加高效
前置++操作符和后置++操作符都可以被重载
++操作符的重载必须符合其原生语义
对于基础类型,前置++与后置++的效率几乎相同
对于类类型,前置++的效率高于后置++