码迷,mamicode.com
首页 > 编程语言 > 详细

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、->运算符重载

时间:2015-08-06 20:32:35      阅读:95      评论:0      收藏:0      [点我收藏+]

标签:c++ primer   c++   操作符重载与转换   

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、->运算符重载

一、成员函数的重载、覆盖与隐藏
    对于类层次的同名成员函数来说,有三种关系:重载、覆盖和隐藏,理清3种关系,有助于写出高质量的代码。 

1、成员函数的重载
    重载的概念相对简单,只有在同一类定义中的同名成员函数才存在重载关系,主要特点时函数的参数类型和数目有所不同;但不能出现函数参数的个数和类型均相同,仅仅依靠返回值类型不同来区分的函数,这和普通函数的重载是完全一致的。另外,重载和成员函数是否虚函数无关,举例来说:
class A
{
    ...
    virtual int fun();
    void fun(int);
    void fun(double, double);
    static int fun(char);
    ...
};
上述A类定义中的4个fun函数便是重载关系。
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)相同的函数名字;
(3)不同的参数列表;
(4)virtual关键字可有可无。

2、成员函数的覆盖
覆盖是指:在派生类中覆盖基类中的同名函数,要求基类函数必须是虚函数,且:
(1)与基类的虚函数有相同的参数个数;
(2)与基类的虚函数有相同的参数类型;
(3)与基类的虚函数有相同的返回类型:或者与基类虚函数相同,或者都返回指针(或引用),并且派生类虚函数所返回的指针(或引用)类型是基类中被替代的虚函数所返回的指针(或引用)类型的子类型(派生类型)。
如下述代码中,B中的fun覆盖了A中的fun。
class A
{
public:
    virtual void fun(int) { }
};
class B: public A
{
public:
    void fun(int) { }
};
覆盖的特征如下:
(1)不同的范围(分别位于派生类与基类)
(2)相同的函数名字;
(3)相同的参数
(4)基类函数必须有virtual关键字

重载与覆盖的区别如下:
(1)覆盖是子类和父类之间的关系,是垂直关系;重载时同一个类中不同方法之间的关系,是水平关系;
(2)覆盖要求参数列表相同,重载要求参数列表不同;覆盖要求返回类型相同,重载则要求不同;
(3)覆盖关系中,调用方法体是根据对象的类型来决定的,重载关系是根据调用时的实参表与形参表来选择方法体的。

3、成员函数的隐藏
隐藏指的是在某些情况下,派生类中的函数屏蔽了基类中的同名函数,这些情况包括:
(1)两个函数参数相同,但基类函数不是虚函数。和覆盖的区别在于基类函数是否是虚函数。如下:
class A
{
public:
    void fun(int) { }
};
class B: public A
{
public:
    void fun(int) { }  //隐藏父类的fun函数
};
上述代码若有:
B b;
b.fun(2);
则调用的将是B中的函数fun,若需调用A中的函数fun,可以以下面的形式调用:
B b;
b.A::fun(2);


(2)两个函数参数不同,无论基类函数是否是虚函数,基类函数都会被屏蔽。和重载函数的区别在于两个函数不在同一个类中。如下述代码:
class A
{
public:
    virtual void fun(int) { }
};
class B: public A
{
public:
    void fun(char) { }  //隐藏父类的fun函数
};
上述代码若有:
B b;
b.fun(2);
则是错误的,因为A中的函数fun被隐藏了,此时编译器找不到参数为int型的fun函数。此时可通过:
B b;
b.A::fun(2);
调用A中的fun函数。

【例子1】
分析以下程序的运行结果()
class A
{
public:
    A() {cout << "construct A" << endl;}
    ~A() {cout << "destroy A" << endl;}
};
class B: public A
{
public:
    B() {cout << "construct B" << endl;}
    ~B() {cout << "destroy B" << endl;}
};
void main()
{
    B obj;
}
A、construct A      
      construct B
      destroy A
      destroy B

B、construct A
      construct B
      destroy B
      destroy A
解答:B。基类的构造函数先执行,析构顺序跟构造函数执行顺序相反。

【例子2】
下面代码中,A的构造函数和析构函数分别执行了()次?
A *pa = new A[10];
delete []pa;
A、1、1         B、10、10         C、1、10          D、10、1
解答:B。数组pa总共有10个A类对象,每个对象都要执行构造函数和析构函数。


二、类型转换运算符

必须是成员函数,不能是友元函数
没有参数
不能指定返回类型
函数原型:operator 类型名();


#include <iostream>
using namespace std;

class Integer
{
public:
    Integer(int n);
    ~Integer();
    Integer &operator++();
    Integer operator++(int n);
    operator int();
    void Display() const;
private:
    int n_;
};

Integer::Integer(int n) : n_(n) { }
Integer::~Integer() { }
Integer &Integer::operator ++()
{
    ++n_;
    return *this;
}

Integer Integer::operator++(int n)
{
    Integer tmp(n_);
    n_++;
    return tmp;
}

Integer::operator int()
{
    return n_;
}

void Integer::Display() const
{
    cout << n_ << endl;
}

int add(int a, int b)
{
    return a + b;
}


int main(void)
{
    Integer n(100);
    n = 200;
    n.Display();
    int sum = add(n, 100);
    cout << sum << endl;
    int x = n;
    int y = static_cast<int>(n);
    return 0;
}

运行结果:

200

300

解释:其中n = 200; 是隐式将int 转换成Interger类;int x = n; 是调用operator int 将Interger 类转换成int,也可以使用static_cast 办到;此外add 函数传参时也会调用operator int 进行转换。


三、->运算符重载

(1)C++中“->“与“.“的区别

->是指针指向其成员的运算符
.是结构体的成员运算符


struct A
{
   int a;
   int b;
};

A *point = malloc(sizeof(struct A));
point->a = 1;

A object;
object.a = 1;


(2)类* operator->(); 与 类& operator*();

#include <iostream>
using namespace std;

class DBHelper
{
public:
    DBHelper()
    {
        cout << "DB ..." << endl;
    }

    ~DBHelper()
    {
        cout << "~DB ..." << endl;
    }

    void Open()
    {
        cout << "Open ..." << endl;
    }

    void Close()
    {
        cout << "Close ..." << endl;
    }

    void Query()
    {
        cout << "Query ..." << endl;
    }
};

class DB
{
public:
    DB()
    {
        db_ = new DBHelper;
    }

    ~DB()
    {
        delete db_;
    }

    DBHelper *operator->()
    {
        return db_;
    }

    DBHelper &operator*()
    {
        return *db_;
    }

private:
    DBHelper *db_;
};


int main(void)
{
    DB db;
    db->Open();
    db->Query();
    db->Close();

    (*db).Open();
    (*db).Query();
    (*db).Close();
    return 0;
}
运行结果:
DB ...
Open ...
Query ...
Close ...
Open ...
Query ...
Close ...
~DB ...


解释:db->Open(); 等价于 (db.operator->())->Open(); 会调用operator-> 返回DBHelper类的指针,调用DBHelper的成员函数Open()。这样使用的好处是不需要知道db 对象什么时候需要释放,当生存期结束时,会调用DB类的析构函数,里面delete db_; 故也会调用DBHelper类的析构函数。

(*db).Open(); 等价于(db.operator*()).Open();


参考:

C++ primer 第四版

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、->运算符重载

标签:c++ primer   c++   操作符重载与转换   

原文地址:http://blog.csdn.net/keyyuanxin/article/details/47321715

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!