C++基础从0到1入门编程(五)使用类-(友元、运算符重载、转换函数)

系统学习C++
方便自己日后复习,错误的地方希望积极指正
往期文章:
C++基础从0到1入门编程(一)
C++基础从0到1入门编程(二)
C++基础从0到1入门编程(三)
C++基础从0到1入门编程(四)
参考视频:
1.黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
2.系统化学习C++


使用类:
(1)友元
(2)运算符重载
(3)转换函数

1 友元

如果想要调用类的私有成员变量,调用类的公有成员是唯一的办法

#include 
using namespace std;
class A
{
public:
    void func()
    {
        cout << a_ << ' ' << b_ << endl;
    }
private:
    int a_ = 0;
    int b_ = 0;
};

int main()
{
    A a;
    a.func(); // 0 0
}

而类的私有成员函数则无法访问

友元提供了另一访问类的私有成员的方案:
(1) 友元全局函数
(2) 友元类
(3) 友元成员函数

友元全局函数:可以访问另一个类的全部成员

#include 
using namespace std;
class CGirl
{
    friend void func(); // 友元全局函数
public:
    string name_;
    CGirl() {name_ = "BigDavid"; xw_ = 87;}
    void show1()
    {
        cout << name_ << endl;
    }
private:
    int    xw_;
    void show2()
    {
        cout << xw_ << endl;
    }
};

void func()
{
    CGirl g;
    g.show1();
    g.show2();
}
int main()
{
    func();
    return 0;
}

友元类
在友元类的成员函数中,都可以访问另一个类的所有成员
Tip:
(1)友元关系不能被继承
(2)友元关系是单向的,不具备交换性

若类B是类A的友元,类A不一定是类B的友元。B是类A的友元,类C是B的友元,类C不一定是类A的友元,要看类中是否有相应的声明。

#include 
using namespace std;
class CGirl
{
    friend class CBoy;
public:
    string name_;
    CGirl() {name_ = "BigDavid"; xw_ = 87;}
    void show1()
    {
        cout << name_ << endl;
    }
private:
    int    xw_;
    void show2() const
    {
        cout << xw_ << endl;
    }
};
class CBoy
{
public:
    void func(const CGirl& g)
    {
        cout << g.name_ << endl;
        cout << g.xw_ << endl;
        g.show2();
    }
};
int main()
{
    CGirl g;
    CBoy b;
    b.func(g);
    return 0;
}

友元成员函数:友元成员函数可以访问另一个类的所有成员,不过对于应用友元成员函数比较繁琐

class CGirl;            // 前置声明
class CBoy { ...... };      // CBoy的定义
class CGirl { ...... };      // CGirl的定义
// 友元成员函数的定义。               
void CBoy::func(CGirl &g) { ...... }
#include 
using namespace std;
class CGirl;// 前置声明

class CBoy // CBoy的定义
{
public:
    void fun(const CGirl& g);
};

class CGirl // CGirl的定义
{
    friend void CBoy::fun(const CGirl& g); // 声名友元成员函数
public:
    CGirl()
    {
        name_ = "BigDavid";
    }
private:
    string name_;
    void show()
    {
        cout << name_ << endl;
    }
};
// 友元成员函数的定义
void CBoy::fun(const CGirl &g) {cout << g.name_ << endl;}
int main()
{
    CGirl g;
    CBoy b;
    b.fun(g);
}

2 运算符重载

2.1 运算符重载基础

C++将运算符扩展到自定义的数据类型,可以让对象操作更美观。
语法:返回值 operator 运算符(参数列表);
运算符重载函数的返回值类型要与运算符本身的含义一致

非成员函数版本的重载运算符函数:形参个数与运算符的操作数个数相同
成员函数版本的重载运算符函数:形参个数比运算符的操作数个数少一个,其中的一个操作数隐式传递了调用对象

重载非成员函数和成员函数版本,两者只能二选一
Tip:
(1)返回自定义数据类型的引用可以让多个运算符表达式串联起来
(2)重载函数参数列表中的顺序决定了操作数的位置
(3)重载函数的参数列表中至少有一个是用户自定义的类型,防止程序员为内置数据类型重载运算符
(4)如果运算符重载既可以是成员函数也可以是全局函数,优先考虑成员函数
(5)重载函数不能违背运算符原来的含义和优先级
(6)不能创建新的运算符
(7)以下运算符不可重载:sizeof..*::?:typeidconst_castdynamic_castreinterpret_caststatic_cast
(8)以下运算符只能通过成员函数重载:=()[],->

#include 
using namespace std;

class CGirl
{
    friend CGirl& operator+(CGirl& g, int score);
    friend CGirl& operator+(int score, CGirl& g);
    friend CGirl& operator+(CGirl& g1, CGirl& g2);
private:
    int xw_;
    int score_;
public:
    string name_;
    CGirl() {name_ = "BigDavid"; xw_ = 87; score_ = 30;}
    void show()
    {
        cout << name_ << ' ' << xw_ << ' ' << score_ << endl;
    }
};

CGirl& operator+(CGirl& g, int score)
{
    g.score_ = g.score_ + score;
    return g;
}
CGirl& operator+(int score, CGirl& g)
{
    g.score_ = g.score_ + score;
    return g;
}
CGirl& operator+(CGirl& g1, CGirl& g2)
{
    g1.score_ = g1.score_ + g2.score_;
    return g1;
}

int main()
{
    CGirl g;
    g + 30;
    g.show(); // 60
    20 + g;   
    g.show(); // 80
    g + g;
    g.show(); // 160
}
2.2 重载关系运算符

六种关系运算符:==,!=,>,>=,<,<=
可以使用非成员函数和成员函数两种版本,建议采用成员函数版本

#include 
using namespace std;
class CGirl
{
    string name_;
    int    yz_;
    int    sc_;
    int    acting_;
public:
    CGirl(string name, int yz, int sc, int acting)
    {
        name_ = name;
        yz_   = yz;
        sc_   = sc;
        acting_= acting;
    }
    bool operator==(const CGirl& g1)
    {
        if ((yz_ + sc_ + acting_) == (g1.yz_ + g1.sc_ + g1.acting_)) return true;
        return false;
    }
    bool operator>(const CGirl& g1)
    {
        if ((yz_ + sc_ + acting_) > (g1.yz_ + g1.sc_ + g1.acting_)) return true;
        return false;
    }
    bool operator<(const CGirl& g1)
    {
        if ((yz_ + sc_ + acting_) < (g1.yz_ + g1.sc_ + g1.acting_)) return true;
        return false;
    }
};

int main()
{
    CGirl g1("Big", 1, 2, 3), g2("Liu", 1, 1, 1);
    if (g1 == g2) cout << "=" << endl;
    else if (g1 < g2) cout << "<" << endl;
    else cout << ">" << endl;
    return 0;
}
2.3 重载左移运算符

重载左移运算符用于输出自定义对象的成员变量,在实际开发中用于调试和输出日志
只能使用非成员函数版本
要输出对象的私有成员,可以配合友元一起使用

#include 
using namespace std;

class CGirl
{
    friend ostream& operator<<(ostream& cout, CGirl& g);
    string name_;
    int    xw_;
    int    score_;
public:
    CGirl() { name_ = "BigDavid"; xw_ = 20; score_ = 30; }
    void show()
    {
        cout << name_ << ' ' << xw_ << ' ' << score_ << endl;
    }
};
ostream& operator<<(ostream& cout, CGirl& g)
{
    cout << g.name_ << ' ' << g.xw_ << ' ' << g.score_ << endl;
    return cout;
}
int main()
{
    CGirl g;
    cout << g << endl;
}
2.4 重载下标运算符

如果对象中有数组,重载下标运算符[],操作对象中的数组将像操作普通数组一样方便。
下标运算符必须以成员函数的形式进行重载
语法:返回值类型 &operator[](参数);或者const 返回值类型 &operator[](参数) const;

返回值类型 &operator[](参数);:[]不仅可以访问数组元素,还可以修改数组元素
const 返回值类型 &operator[](参数) const;:[]只能访问而不能修改数组元素

实际开发应该同时提供以上两种形式,这样做是为了适应const对象,因为通过const 对象只能调用const成员函数,如果不提供第二种形式,那么将无法访问const对象的任何数组元素

在重载函数中,可以对下标做合法性检查,防止数组越界

#include 
using namespace std;
class CGirl
{
private:
    string boys[3];
public:
    string name_;
    CGirl() { boys[0] = "BigDavid"; boys[1] = "qwe"; boys[2] = "Liu"; }
    void show() { cout << boys[0] << ' ' << boys[1] << ' ' << boys[2] << endl; }
    string& operator[](int i)
    {
        return boys[i];
    }
    const string& operator[](int i) const
    {
        return boys[i];
    }
};
int main()
{
    CGirl g;
    g[1] = "LiuXueJin";
    cout << g[1] << endl;
    g.show();

    const CGirl g1 = g;
    cout << g1[1] << endl;
}
2.5 重载赋值运算符

C++编译器可能会给类添加四个函数:
默认构造函数:空实现
默认析构函数:空实现
默认拷贝构造函数:对成员变量浅拷贝
默认赋值函数:对成员变量浅拷贝

(1)对象的赋值运算是用一个已经存在的对象,给另外一个已经存在的对象赋值
(2)如果类中重载了赋值函数,编译器将不提供默认赋值函数。没有重载,编译器提供默认赋值函数

语法:类名& operator=(const 类名& 源对象);
Tip
1.编译器提供的默认赋值函数,是浅拷贝
2.如果对象不存在堆区内存空间,默认赋值函数可以满足需求,否则需要深拷贝
3.赋值运算和拷贝构造不同:拷贝构造是指原来的对象不存在,用已存在的对象进行构造;赋值运算是存在两个对象,把其中一个对象的成员变量的值赋给另一个对象的成员变量。

#include 
#include 
using namespace std;

class CGirl
{
public:
    int    bh_;
    string name_;
    int*   ptr_; // 计划使用堆区内存
    CGirl() { ptr_ = nullptr; }
    ~CGirl() { if(ptr_) delete ptr_; }
    void show()
    {
        cout << bh_ << ' ' << name_ << ' ' << ptr_ << endl;
    }
    CGirl& operator=(const CGirl& g)
    {
        if (this == &g) return *this; // 自己给自己赋值
        if (g.ptr_ == nullptr) // 如果源对象的指针为空,则清空目标对象的内存和指针
        {
            if (ptr_ != nullptr) { delete ptr_; ptr_ = nullptr; }
        }
        else // 如果源对象的指针不为空
        {
            if (ptr_ == nullptr) ptr_ = new int; // 如果目标对象的指针为空,先分配内存
            memcpy(ptr_, g.ptr_, sizeof(int)); // 然后,将源对象内存中的数据复制到目标对象的内存中
        }
        bh_ = g.bh_;
        name_ = g.name_;
        cout << "chongzaifuzhi" << endl;
        return *this;
    }
};
int main()
{
    CGirl g1, g2;
    g1.bh_ = 8;
    g1.name_ = "Big";
    g1.ptr_ = new int(4);
    g1.show(); // 8 Big 0x1f9276318c0
    g2.show(); // 1484781408  0
    g2 = g1;   // chongzaifuzhi
    g2.show(); // 8 Big 0x1f9276318e0
}
2.6 重载new/delete运算符

重载new和delete运算符是为了自定义内存分配的细节
在C++中
使用new,编译器做了两件事情:
(1)调用标准库函数operator new()分配内存
(2)调用构造函数初始化内存
使用delete时,编译器做了两件事情:
(1)调用析构函数
(2)调用标准库函数operator delete()释放内存
构造函数和析构函数由编译器调用,我们无法控制。
可以重载内存分配函数operator new()和释放函数operator delete()
1.重载内存分配函数
void* operator new(size_t size);
2.重载内存释放函数
void operator delete(void* ptr);
重载的new和delete可以是全局函数,也可以是类的成员函数
为一个类重载new和delete,实际上仍在创建static成员函数

编译器看到使用new创建自定义的类的对象时,它选择成员版本的operator new()而不是全局版本的new()

new[]和delete[]也可以重载

#include 
using namespace std;
void* operator new(size_t size)
{
    cout << "QJ new" << size << endl;
    void* ptr = malloc(size);
    cout << ptr << endl;
    return ptr;
}
void operator delete(void* ptr)
{
    cout << "QJ delete" << endl;
    if (ptr == 0) return;
    free(ptr);
}

class CGirl
{
public:
    int bh_;
    int xw_;
    CGirl(int bh, int xw) { bh_ = bh, xw_ = xw; cout << "GouZao" << endl; }
    ~CGirl() { cout << "~CGirl()" << endl; }
    void* operator new(size_t size)
    {
        cout << "Dy Lei new" << endl;
        void* ptr = malloc(size);
        cout << ptr << endl;
        return ptr;
    }
    void operator delete(void* ptr)
    {
        cout << "Dy Lei delete" << endl;
        if (ptr == 0) return;
        free(ptr);
    }
};
int main()
{
    int* p1 = new int(3);
    cout << "p1=" << (void*)p1 << ' ' << "*p1=" << *p1 << endl;
    delete p1;
    CGirl* p2 = new CGirl(3, 8);
    cout << p2 << ' ' << p2->bh_ << p2->xw_ << endl;
    delete p2;
}
/*
 * QJ new4
 * 0x24957a618c0
 * p1=0x24957a618c0 *p1=3
 * Dy Lei new
 * 0x24957a618c0
 * GouZao
 * 0x24957a618c0 38
 * ~CGirl()
 * Dy Lei delete
 */
2.7 实现简单的内存池

内存池:预先分配一大块的内存空间
(1)提升分配和归还的速度
(2)减少内存碎片

#include 
#include 
using namespace std;
class CGirl
{
public:
    int bh_;
    int xw_;
    static char* pool_;
    static bool initpool() // 初始化内存池的函数
    {
        pool_ = (char*)malloc(18); // 向系统申请18字节的内存
        if (pool_ == 0) return false;   // 申请内存失败
        memset(pool_, 0, 18);
        cout << "Start address: " << (void*)pool_ << endl;
        return true;
    }
    static void freepool()     // 释放内存池
    {
        if (pool_ == 0) return;// 如果内存池为空,不需要释放
        free(pool_);   // 把内存池还给系统
        cout << "Free finish" << endl;
    }
    CGirl(int bh, int xw) { bh_ = bh, xw_ = xw; cout << "CGirl()\n"; }
    ~CGirl() { cout << "~CGirl\n"; }
    void* operator new(size_t size)
    {
        if (pool_[0] == 0) // 判断第一个位置是否空闲
        {
            cout << "fenpei first neicun: " << (void*)(pool_ + 1) << endl;
            pool_[0] = 1; // 把第一个位置标记为已分配
            return pool_ + 1; // 返回第一个用于存放对象的址
        }
        if (pool_[9] == 0)// 判断第二个位置是否空闲
        {
            cout << "fenpei second neicun: " << (void*)(pool_ + 9) << endl;
            pool_[9] = 1;// 把第二个位置标记为已分配
            return pool_ + 9;// 返回第二个用于存放对象的址
        }
        // 如果以上两个位置都不可用,那就直接系统申请内存
        void* ptr = malloc(size);// 申请内存
        cout << ptr << endl;
        return ptr;
    }
    void operator delete(void* ptr)
    {
        if (ptr == 0) return;// 如果传进来的地址为空,直接返回
        if (ptr == pool_ + 1) // 如果传进来的地址是内存池的第一个位置
        {
            cout << "Free first neicun\n";
            pool_[0] = 0;// 把第一个位置标记为空闲
            return;
        }
        if (ptr == pool_ + 9)// 如果传进来的地址是内存池的第二个位置
        {
            cout << "Free second neicun\n";// 把第二个位置标记为空闲
            pool_[9] = 0;
            return;
        }
        free(ptr);// 如果传进来的地址不属于内存池,把它归还给系统
    }
};
char* CGirl::pool_ = 0;// 初始化内存池的指针
int main()
{
    if (CGirl::initpool() == false) { cout << "init false\n"; return -1; }// 初始化内存池
    CGirl* p1 = new CGirl(3, 8);// 将使用内存池的第一个位置
    cout << p1 << ' ' << p1->bh_ << ' ' << p1->xw_ << endl;
    CGirl* p2 = new CGirl(4, 7);// 将使用内存池的第二个位置
    cout << p2 << ' ' << p2->bh_ << ' ' << p2->xw_ << endl;
    CGirl* p3 = new CGirl(6, 9);// 将使用系统的内存
    cout << p3 << ' ' << p3->bh_ << ' ' << p3->xw_ << endl;
    delete p1;// 将释放内存池的第一个位置
    CGirl* p4 = new CGirl(5, 3);// 将使用内存池的第一个位置
    cout << p4 << ' ' << p4->bh_ << ' ' << p4->xw_ << endl;
    delete p2;// 将释放内存池的第二个位置
    delete p3;// 将释放系统的内存
    delete p4;// 将释放内存池的第一个位置
    CGirl::freepool(); // 释放内存池
}
2.8 重载括号运算符

重载括号运算符,对象名可以当作函数来使用(函数对象、仿函数)
语法:返回值类型 operator()(参数列表);
Tip:
(1)括号运算符必须以成员函数形式重载

#include 
using namespace std;
void show(string str)
{
    cout << "Common: " << str << endl;
}
class CGirl
{
public:
    void operator()(string str)
    {
        cout << "CZHanshu: " << str << endl;
    }
    void operator()(int i)
    {
        cout << i << endl;
    }
};
int main()
{
    CGirl g;
    g("asd");   // CZHanshu: asd
    g(8);        // 8
    show("asd");// Common: asd
    return 0;
}

(2)括号运算符重载函数具备普通函数的全部特征
(3)如果函数对象与全局函数同名,按照作用域规则选择调用的函数

#include 
using namespace std;
void show(string str)
{
    cout << "Common: " << str << endl;
}
class CGirl
{
public:
    void operator()(string str)
    {
        cout << "CZHanshu: " << str << endl;
    }
    void operator()(int i)
    {
        cout << i << endl;
    }
};
int main()
{
    show("asd"); // Common: asd
    CGirl show;
    show("asd"); // CZHanshu: asd
    ::show("asd"); // Common: asd
    return 0;
}

函数对象的用途:
(1)表面像函数,部分场景可以代替函数,在STL中有广泛应用
(2)函数对象本质是类,可以用成员变量存放更多的信息
(3)函数对象有自己的数据类型
(4)可以提供继承体系

2.9 重载一元运算符

可重载的一元运算符
(1)++ 自增
(2)-- 自减
(3)! 逻辑非
(4)& 取地址
(5)~ 二进制反码
(6)* 解引用
(7)+ 一元加
(8)- 一元求反
一元运算符通常出现在他们操作对象的左边
自增运算符++和自减运算符--有前置和后置之分
C++ 规定,重载++或- -时,如果重载函数有一个int形参,编译器处理后置表达式时将调用这个重载函数。

++前置 成员函数版:CGirl &operator++();
后置++ 成员函数版:CGirl operator++(int);
++前置 非成员函数版:CGirl &operator++(CGirl &);
后置++ 非成员函数版:CGirl operator++(CGirl &,int);

#include 
using namespace std;
class CGirl
{
public:
    string name_;
    int    ranking_;
    CGirl() { name_ = "BigDavid"; ranking_ = 5; }
    void show() const { cout << name_ << ' ' << ranking_ << endl; }
    CGirl& operator++()   // ++前置的重载函数
    {
        ranking_++;
        return *this;
    }
    CGirl operator++(int) // ++后置的重载函数
    {
        CGirl tmp = *this;
        ranking_++;
        return tmp;
    }
};
int main()
{
    CGirl g1, g2;
    int i = 5, j = 5;
    int x = ++(++(++i));
    int y = j++;
    cout << x << ' ' << y << endl;                  // 8 5
    CGirl g3 = ++(++(++g1));
    cout << g3.name_ << ' ' << g3.ranking_ << endl; // BigDavid 8
    CGirl g4 = g2++;
    cout << g4.name_ << ' ' << g4.ranking_ << endl; // BigDavid 5
}

3 C++类型转换

3.1 自动类型转换

对于内置数据类型,如果两种数据类型是兼容的,C
++可以自动转换,如果从更大的数转换为更小的数,可能会被截断或损失精度‘。
C++不自动转换不兼容的类型,非法:int* ptr = 8;
不能自动转换,可以使用强制类型转换:int* p = (int*)8;
如果某种类型与类相关,从某种类型转换为类类型是有意义的

#include 
using namespace std;
class CGirl
{
public:
    int    bh_;
    string name_;
    double weight_;
    CGirl() { bh_ = 0; name_.clear(); weight_ = 8; cout << "CGirl()\n"; }
    void show() { cout << bh_ << ' ' << name_ << ' ' << weight_ << endl; }
    explicit CGirl(int bh)
    {
        bh_ = bh;
        name_.clear();
        weight_ = 0;
        cout << "CGirl(int bh)\n";
    }
    CGirl(double weight) { bh_ = 0; name_.clear(); weight_ = weight; cout << "CGirl(double weight)\n"; }
};
int main()
{
    // CGirl g1(8); // 常规写法
    //CGirl g1 = CGirl(8);// 显式转换
    //CGirl g1 = 8;// 隐式转换
    //CGirl g1;// 创建对象
    //g1 = (CGirl)8;// 隐式转换,用CGirl(8)创建临时对象,再赋值给g
    CGirl g1 = 8.9;// 隐式转换
    //g1.show();
}

Tip:
(1)一个类可以有多个转换函数
(2)多个参数的构造函数,除第一个参数外,如果其它参数都有缺省值,也可以作为转换函数
(3)在实际开发中,如果强调的是构造,建议使用explicit,如果强调的是类型转换,则不使用explicit
(4)将构造函数用作自动类型转换函数似乎是一项不错的特性,但有时候会导致意外的类型转换。explicit关键字用于关闭这种自动特性,但仍允许显式转换

explicit CGirl(int bh);
CGirl g = 8; // 不行
CGirl g = CGirl(8);
CGirl g = (CGirl)8;

(5)如果自动类型转换有二义性,编译报错

CGirl(int)的隐式转换的场景:

1.将CGirl对象初始化为int值

CGirl g1 = 8;

2.将int值赋给CGirl对象

CGirl g1; g1 = 8;

3.将int值传递给接受CGirl参数的函数

#include 
using namespace std;
class CGirl
{
public:
    int    bh_;
    string name_;
    double weight_;
    CGirl() { bh_ = 0; name_.clear(); weight_ = 8; cout << "CGirl()\n"; }
    void show() { cout << bh_ << ' ' << name_ << ' ' << weight_ << endl; }
    CGirl(int bh)
    {
        bh_ = bh;
        name_.clear();
        weight_ = 0;
        cout << "CGirl(int bh)\n";
    }
    CGirl(double weight) { bh_ = 0; name_.clear(); weight_ = weight; cout << "CGirl(double weight)\n"; }
};
void fun(CGirl g)
{
    g.show();
}
int main()
{
    // CGirl g1(8); // 常规写法
    //CGirl g1 = CGirl(8);// 显式转换
    //CGirl g1 = 8;// 隐式转换
    //CGirl g1;// 创建对象
    //g1 = (CGirl)8;// 隐式转换,用CGirl(8)创建临时对象,再赋值给g
    //CGirl g1 = 8.9;// 隐式转换
    //g1.show();
    fun(7); // 7 0
}

4.返回值被声明为CGirl的函数试图返回int值

#include 
using namespace std;
class CGirl
{
public:
    int    bh_;
    string name_;
    double weight_;
    CGirl() { bh_ = 0; name_.clear(); weight_ = 8; cout << "CGirl()\n"; }
    void show() { cout << bh_ << ' ' << name_ << ' ' << weight_ << endl; }
    CGirl(int bh)
    {
        bh_ = bh;
        name_.clear();
        weight_ = 0;
        cout << "CGirl(int bh)\n";
    }
    CGirl(double weight) { bh_ = 0; name_.clear(); weight_ = weight; cout << "CGirl(double weight)\n"; }
};
CGirl func()
{
    char c = 8;
    return c;
    // return 8;
}
int main()
{
    // CGirl g1(8); // 常规写法
    //CGirl g1 = CGirl(8);// 显式转换
    //CGirl g1 = 8;// 隐式转换
    //CGirl g1;// 创建对象
    //g1 = (CGirl)8;// 隐式转换,用CGirl(8)创建临时对象,再赋值给g
    //CGirl g1 = 8.9;// 隐式转换
    //g1.show();
    func(); // CGirl(int bh)
}
3.2 转换函数

构造函数只用于从某种类型到类类型的转换,如果要进行相反的转换,可以使用特殊的运算符函数-转换函数
语法:operator 数据类型();
Tip:转换函数必须是类的成员函数;不能指定返回值类型;不能有参数
可以让编译器决定选择转换函数(隐式转换),可以像使用强制类型转换那样使用它们(显式转换)

int i = girl;      // 隐式转换
int i = (int)girl; // 显示转换
int i = int(girl); // 显示转换

隐式转换存在二义性,编译器将报错
在C++98中,关键字explicit不能用于转换函数,但C++11消除了这种限制,可以将转换函数声明为显式的
经常用:用一个功能相同的普通成员函数代替转换函数,普通成员函数只有被调用时才会执行

应谨慎的使用隐式转换函数。通常,最好选择仅在被显式地调用时才会执行的成员函数

#include 
using namespace std;
class CGirl
{
public:
    int    bh_;
    string name_;
    double weight_;
    CGirl() { bh_ = 8; name_ = "Big"; weight_ = 40.2; }
    explicit operator int() { return bh_; }
    int to_int() { return bh_; }
    operator string() { return name_; }
    explicit operator double() { return weight_; }
};
int main()
{
    string name_ = "Big";
    // const char* ptr = name_;
    const char* ptr = name_.c_str();
    CGirl g;
    int a = g.to_int(); cout << a << endl;  // 8
    string b = string(g); cout << b << endl;// Big
    double c = double(g); cout << c << endl;// 40.2
    short d = (int)g; cout << d << endl;    // 8
}

你可能感兴趣的:(C++,c++)