运算符重载实例(有理数的运算)

摘自Effective c++关于const 的用法介绍:

1、对于基本类型声明:

const int i = 1;

int const i = 1;

两种写法本质都是标准const变量声明加初始化,i为常量,不可修改。因为默认为内部连接,所以必须被初始化,其作用域为此文件,编译器经过类型检查后直接用100在编译时替换。//与#define不同的是const在编译期间被替换,也就是说记号名称被写入了符号表。

extend const int i  = 100; 

const改为外部连接,作用域为全局,在编译时分配内存。可以不初始化,仅作为声明,编译器将认为在别的地方进行初始化。

const int  arr[] = { 1, 2, 3, 4};

struct  S { int a, b};

const  S  s[] = { ( 1, 2), ( 3, 4) };

两种都是常量集合,在编译期间会被分配内存,在编译期间无法使用其值,例如 int  arr_s[ arr[2] ] 将报错,提示不能找到常量表达式。

 

2、const修饰指针

引述effective C++,如果const出现在*号左边,修饰的是指针指向的对象,被指对象是常量,即对象不可修改。如果const出现在*号右边,修饰的是指针本身,指针本身是常量,即指针不能再指向别的内存。如果const出现在*号两边,则指针和被指对象均是常量。

const int *p = &x;   //x是常量

int const *p = &x;  //x是常量

int* const p = &x;  //指针p是常量

const int * const p = &x;   //指针p和变量x均是常量

 

3、const修饰函数参数

这是const的最广泛的用途之一。

void function(const int param);    //无意义,pass-by-value,此处传递的是实参的副本

 void function(const int* p);    //指针指向的对象在函数体内不可被修改

void function(int* const param);    //无意义, 指针本身是常量

当参数为引用

void function(const CLASS_TYPE& param);     //参数在函数体内不可被修改 

void function(const TYPE&  param);     //参数为在函数体内为常量

 

4、const修饰函数返回值

const TYPE function();    //无意义,返回的是return expression的拷贝

const TYPE* function();   // const TYPE* p = function();  p指向的的内存内容不可修改

TYPE* const function();   //TYPE*  const p = function();  指针p本身是常量,不可再指向其他内存

const TYPE& function();     //返回的是常量值,且非常安全。

//安全性    例:有函数声明const Rational operator*  (const Rational& lhs, const Rational& rhs);

if(a * b = c){....}   //原意其实仅仅是想比较?

避免返回值被修改,上式非法。

 

5、const修饰类对象/类对象指针/类对象引用

当const修饰类对象时,对象为常量对象。表示此对象的任何成员都不能被修改。

常量对象的非常量成员函数都不能被调用,因为非常量成员函数有修改类成员的可能。

class A
{
    public:
        int function_1();
        int function_2() const;
    .....
};

const A  Object_a;

Object_a->function_1();   //非法

Object_a->function_2();    //合法

const A* Object_b = new A();

Object_b->function_1();    //非法

Object_b->function_2();    //合法

 

6、const修饰类成员

class A
{
    private:
        const int a;    //类成员为常量,不能被修改
        ...
    public:
        A(int r):a(r){}   //常成员变量只能在构造函数的初始化列表中初始化
        A(int r)
        {
            a = r;         //error,这是赋值,不是初始化
        }
        ...
};

 

7、const修饰类成员函数

const修饰类成员函数,则该函数不能修改类成员,也不能调用类的非const成员函数。

class A
{
    ...
    int function() const;   //function不能修改任何类成员,也不能调用非const类成员函数
    ...
};

根据6,const 对象/对象指针/对象引用 只能调用const成员函数。

注意:

两个函数如果只是常量性不同,可以被重载。

class TextBlock
{
    ...
    public:
        const char& operator [] (int position) const
        char& operator [] (int position);
        ...
    private:
        string text;
};

 为了const和non-const成员函数中避免重复,可以在non-const成员函数实现中调用const成员函数。

class TextBlock
{
    ...
    public:
        const char& operator [] (int position) const
        {
            ...
            return text[position];
        }
        char& operator [] (int position)
        {
            return const_cast<char&>(static_cast<const TextBlock&>(this*)[position]);
        }
        ...
    private:
        string text;
};

注意:

使用的是non-const成员函数调用const版本,因为const版本不会修改对象。反之,若const版本调用non-const版本,则对象在non-const版本中可能被修改,从而导致的连锁反应是const版本在调用non-const版本的过程中,对象可能被修改。

 

8、对于字符数组和临时对象

char* str = "hello world!";

str是常量字符数组,任何想对str进行修改的操作可以通过编译,但是会引起运行时错误。

若想修改字符数组,应该声明为   char str[] = "hello world!";

注意:

临时对象都是常量;

 

9、对于类型检查

可以将一个非const对象赋给指向const的指针,因为不能通过这个指针修改对象的值。不可以将一个const对象赋给指向非const的指针,因为可能通过从这个指针修改对象的值。若想后者合法,可以通过类型转换去掉const的常量性,语法如下:

const int i  =  100;

int* pi = &i;   //非法

int*  pi   = const_cast<int*>(&i);    //const_cast 去掉了i的常量特性


#include <stdio.h>
#include <cmath>
#include <iostream>

using namespace std;
class Rational{
private:
    int num,den;
public:
    Rational(int n , int d = 1);
    Rational();
    void setData(int n,int d);
    void simplify();
    void show();
    bool operator<(const Rational &);
    bool operator<=(const Rational &)const;
    friend bool operator>(const Rational &,const Rational &);
    friend bool operator>=(const Rational &,const Rational &);
    bool operator==(const Rational &)const;
    bool operator!=(const Rational &)const;
    friend Rational operator+(const Rational &,const Rational &);
    friend Rational operator-(const Rational &,const Rational &);
    friend Rational operator*(const Rational &,const Rational &);
    friend Rational operator/(const Rational &,const Rational &);
    Rational operator-();
    operator double();
};
Rational::Rational(int n,int d){
    num = n; den = d;
    simplify();
}
Rational::Rational(){
    num = 1;den = 1;
}
void Rational::setData(int n, int d){
    num = n; den = d;
    simplify();
}
void Rational::simplify(){
    int min;
    if(num < den)
        min = num;
    else
        min = den;
    for(int i = min;i >= 2;i--){
        if(num%i == 0 && den%i == 0){
            num = num/i;
            den = den/i;
        }
    }
}
bool Rational::operator<(const Rational &r){
    return num*r.den < r.num*den;
}
bool Rational::operator<=(const Rational &r)const{
    return num*r.den <= r.num*den;
}
bool operator>(const Rational &r1,const Rational &r2){
    return r1.num*r2.den > r2.num*r1.den;
}
bool operator>=(const Rational &r1,const Rational &r2){
    return r1.num*r2.den >= r2.num*r1.den;
}
bool Rational::operator==(const Rational &r)const{
    return num*r.den == r.num*den;
}
bool Rational::operator!=(const Rational &r)const{
    return num*r.den != r.num*den;
}
Rational operator+(const Rational &r1,const Rational &r2){
    Rational temp;
    temp.num = r1.num*r2.den + r2.num*r1.den;
    temp.den = r1.den*r2.den;
    temp.simplify();
    return temp;
}
Rational operator-(const Rational &r1,const Rational &r2){
    Rational temp;
    temp.num = r1.num*r2.den - r2.num*r1.den;
    temp.den = r1.den*r2.den;
    temp.simplify();
    return temp;
}
Rational operator*(const Rational &r1,const Rational &r2){
    Rational temp;
    temp.num = r1.num*r2.num;
    temp.den = r1.den*r2.den;
    temp.simplify();
    return temp;
}
Rational operator/(const Rational &r1,const Rational &r2){
    Rational temp;
    temp.num = r1.num*r2.den;
    temp.den = r1.den*r2.num;
    temp.simplify();
    return temp;
}
Rational Rational::operator-(){
    return Rational(-num,den);
}
void Rational::show(){
    simplify();
    cout<<num<<"/"<<den<<endl;
}
Rational:: operator double(){
    return double(num)/den;
}
int main(){
    Rational a(4,5),b(16,24),c;
    a.show();
    b.show();
    if(a<b)
        cout<<"a<b"<<endl;
    else if(a == b)
        cout<<"a==b"<<endl;
    else
        cout<<"a>b"<<endl;
    c = a+b;
    c.show();
    c = a-b;
    c.show();
    c = a*b;
    c.show();
    c = a/b;
    c.show();
    c = -a;
    c.show();
    cout<<double(c)<<endl;
        
    return 0;
}


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值