0.目录

1.智能指针

2.转换构造函数

3.类型转换函数

4.小结

1.智能指针

内存泄漏(臭名昭著的Bug):

  • 动态申请堆空间,用完后不归还
  • C++语言中没有垃圾回收机制
  • 指针无法控制所指堆空间的生命周期

我们需要什么:

  • 需要一个特殊的指针
  • 指针生命周期结束时主动释放堆空间
  • 一片堆空间最多只能由一个指针标识
  • 杜绝指针运算和指针比较

解决方案:

  • 重载指针特征操作符( -> 和 * )
  • 只能通过类的成员函数重载
  • 重载函数不能使用参数
  • 只能定义一个重载函数

示例——实现智能指针:

#include <iostream>
#include <string> using namespace std; class Test
{
int i;
public:
Test(int i)
{
cout << "Test(int i)" << endl;
this->i = i;
}
int value()
{
return i;
}
~Test()
{
cout << "~Test()" << endl;
}
}; class Pointer
{
Test* mp;
public:
Pointer(Test* p = NULL)
{
mp = p;
}
Pointer(const Pointer& obj)
{
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
}
Pointer& operator = (const Pointer& obj)
{
if( this != &obj )
{
delete mp;
mp = obj.mp;
const_cast<Pointer&>(obj).mp = NULL;
} return *this;
}
Test* operator -> ()
{
return mp;
}
Test& operator * ()
{
return *mp;
}
bool isNull()
{
return (mp == NULL);
}
~Pointer()
{
delete mp;
}
}; int main()
{
Pointer p1 = new Test(3); cout << p1->value() << endl; Pointer p2 = p1; cout << p1.isNull() << endl; cout << p2->value() << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Test(int i)
3
1
3
~Test()

智能指针的使用军规——只能用来指向堆空间中的对象或者变量

2.转换构造函数

再论类型转换:

C语言标准数据类型之间会进行隐式的类型安全转换

C语言转换规则如下:



(C语言编译器支持从小类型(占用内存少)转换到大类型(占用内存多)的隐式类型转换,因为这样的转换是安全的,不会发生数据截断或者数据丢失。)

示例——隐式类型转换的bug:

#include <iostream>
#include <string> using namespace std; int main()
{
short s = 'a';
unsigned int ui = 1000;
int i = -2000;
double d = i; cout << "d = " << d << endl;
cout << "ui = " << ui << endl;
cout << "ui + i = " << ui + i << endl; if( (ui + i) > 0 )
{
cout << "Positive" << endl;
}
else
{
cout << "Negative" << endl;
} cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
d = -2000
ui = 1000
ui + i = 4294966296
Positive
sizeof(s + 'b') = 4

(在大多数编译器看来,int类型,也就是4个字节的整型数的运算是最高效的。而在sizeof(s + 'b')中,是做加法运算,左操作数和右操作数都可以安全的转换为int,那么可以采用更高效的方式来进行运算。于是就出现bug了!)

问题:

普通类型与类类型之间能否进行类型转换?

类类型之间能否进行类型转换?

再论构造函数:

  • 构造函数可以定义不同类型的参数
  • 参数满足下列条件时称为转换构造函数
    1. 有且仅有一个参数
    2. 参数是基本类型
    3. 参数是其它类类型

旧式的C方式强制类型转换:

编译器会尽力尝试让源码通过编译(普通类型->类类型):

示例——编译器自作聪明的行为:

#include <iostream>
#include <string> using namespace std; class Test
{
int mValue;
public:
Test() { mValue = 0; } Test(int i) { mValue = i; } Test operator + (const Test& p)
{
Test ret(mValue + p.mValue); return ret;
} int value() { return mValue; }
}; int main()
{
Test t;
t = 5; // t = Test(5); Test r;
r = t + 10; // r = t + Test(10); cout << r.value() << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
15

编译器尽力尝试的结果是隐式类型转换。

隐式类型转换:

  • 会让程序以意想不到的方式进行工作
  • 是工程中bug的重要来源

工程中通过explicit关键字杜绝编译器的转换尝试

转换构造函数被explicit修饰时只能进行显示转换

转换方式:

示例——杜绝编译器的转换尝试:

#include <iostream>
#include <string> using namespace std; class Test
{
int mValue;
public:
Test() { mValue = 0; } explicit Test(int i) { mValue = i; } Test operator + (const Test& p)
{
Test ret(mValue + p.mValue); return ret;
} int value() { return mValue; }
}; int main()
{
Test t;
t = static_cast<Test>(5); // t = Test(5); Test r;
r = t + static_cast<Test>(10); // r = t + Test(10); cout << r.value() << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
15

3.类型转换函数

问题:

类类型是否能够类型转换到普通类型?

类型转换函数:

  • C++类中可以定义类型转换函数
  • 类型转换函数用于将类对象转换为其它类型
  • 语法规则:

示例——只有想不到,没有做不到:

#include <iostream>

using namespace std;

class Test
{
int mValue;
public:
Test(int i = 0) { mValue = i; }
operator int() { return mValue; }
}; int main()
{
Test t(100);
int i = t; // ==> t.operator int() cout << "i = " << i << endl; return 0;
}

运行结果为:

[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
i = 100

类型转换函数:

  • 与转换构造函数具有同等的地位
  • 使得编译器有能力将对象转化为其它类型
  • 编译器能够隐式的使用类型转换函数

编译器会尽力尝试让源码通过编译:

类型转换函数 vs 转换构造函数:

  • 无法抑制隐式的类型转换函数调用
  • 类型转换函数可能与转换构造函数冲突
  • 工程中以Type toType()的公有成员代替类型转换函数

示例——能通过编译的类型转换函数:

#include <iostream>
#include <string> using namespace std; class Test; class Value
{
public:
Value() {}
}; class Test
{
int mValue;
public:
Test(int i = 0) { mValue = i; }
int value() { return mValue; }
operator Value()
{
Value ret;
cout << "operator Value()" << endl;
return ret;
}
}; int main()
{
Test t(100);
Value v = t; // ==> t.operator Value() return 0;
}

示例——能通过编译的转换构造函数:

#include <iostream>
#include <string> using namespace std; class Test; class Value
{
public:
Value() {}
Value(Test& t) {}
}; class Test
{
int mValue;
public:
Test(int i = 0) { mValue = i; }
int value() { return mValue; }
}; int main()
{
Test t(100);
Value v = t; // ==> Value(t) return 0;
}

示例——冲突的类型转换函数与转换构造函数:

#include <iostream>
#include <string> using namespace std; class Test; class Value
{
public:
Value() {}
Value(Test& t) {}
}; class Test
{
int mValue;
public:
Test(int i = 0) { mValue = i; }
int value() { return mValue; }
operator Value()
{
Value ret;
cout << "operator Value()" << endl;
return ret;
}
}; int main()
{
Test t(100);
Value v = t; return 0;
}

报错信息为:

[root@bogon Desktop]# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:32: error: conversion from ‘Test’ to ‘Value’ is ambiguous
test.cpp:21: note: candidates are: Test::operator Value()
test.cpp:12: note: Value::Value(Test&)

示例——使用explicit关键字避免冲突:

#include <iostream>
#include <string> using namespace std; class Test; class Value
{
public:
Value() {}
explicit Value(Test& t) {}
}; class Test
{
int mValue;
public:
Test(int i = 0) { mValue = i; }
int value() { return mValue; }
operator Value()
{
Value ret;
cout << "operator Value()" << endl;
return ret;
}
}; int main()
{
Test t(100);
Value v = t; return 0;
}

4.小结

  • 指针特征操作符( -> 和 * )可以被重载
  • 重载指针特征符能够使用对象代替指针
  • 智能指针只能用于指向堆空间中的内存
  • 智能指针的意义在于最大程度的避免内存问题
  • 转换构造函数只有一个参数
  • 转换构造函数的参数类型是其它类型
  • 转换构造函数在类型转换时被调用
  • 隐式类型转换是I程中bug的重要来源
  • explicit关键字用于杜绝隐式类型转换
  • C++类中可以定义类型转换函数
  • 类型转换函数用于将类对象转换为其它类型
  • 类型转换函数与转换构造函数具有同等的地位
  • 工程中以Type toType()的公有成员代替类型转换函数

C++解析(20):智能指针与类型转换函数的更多相关文章

  1. lambda、pair、智能指针及时间函数

    Lambda 表达式 auto f1 = [](int x, int y) { return x + y; };cout << f1(2, 3) << endl; int n ...

  2. [3] 智能指针std::auto_ptr

    [1]std::auto_ptr 对于编译器来说,智能指针实质是一个栈对象,而并非指针类型. 智能指针通过构造函数获取堆内存的管理所有权,而在其生命期结束时,再通过析构函数释放由它所管理的堆内存. 所 ...

  3. C++ 11 智能指针 lamda 以及一个 围棋程序

    lamda表达式使用 char* p = "Hello world"; ,nl = ; for_each(p,p+, [&](char i){ if(i=='e') ne+ ...

  4. 详解C++11智能指针

    前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用. C++11智能指针介 ...

  5. C++智能指针的enable_shared_from_this和shared_from_this机制

    前言 之前学习muduo网络库的时候,看到作者陈硕用到了enable_shared_from_this和shared_from_this,一直对此概念是一个模糊的认识,隐约记着这个机制是在计数器智能指 ...

  6. [Reprint]C++普通函数指针与成员函数指针实例解析

    这篇文章主要介绍了C++普通函数指针与成员函数指针,很重要的知识点,需要的朋友可以参考下   C++的函数指针(function pointer)是通过指向函数的指针间接调用函数.相信很多人对指向一般 ...

  7. 第20课 unique_ptr独占型智能指针

    一. unique_ptr的基本用法 (一)初始化方式 1. 直接初始化:unique<T> myPtr(new T);  //ok.但不能通过隐式转换来构造,如unique<T&g ...

  8. C++ 11 智能指针(shared_ptr)类成员函数详解

    C++ 11 模板库的 <memory> 头文件中定义的智能指针,即 shared_ptr 模板类,用来管理指针的存储,提供有限的内存回收函数,可同时与其他对象共享该管理功能. share ...

  9. 智能指针 shared_ptr 解析

    近期正在进行<Effective C++>的第二遍阅读,书里面多个条款涉及到了shared_ptr智能指针,介绍的太分散,学习起来麻烦.写篇blog整理一下. LinJM   @HQU s ...

随机推荐

  1. css布局笔记(一)

    布局方式 一列布局 通常固定宽高,用margin:0 auto:居中显示 两列布局 说起两列布局,最常见的就是使用float来实现.float浮动布局的缺点是浮动后会造成文本环绕等效果,以及需要及时清 ...

  2. Android 测试 之adb shell

    一.发送键盘事件: 命令格式1:adb shell input keyevent "value" 其中value以及对应的key code如下表所列: KeyEvent Value ...

  3. Unity学习笔记(2): 如何使物体消失

    Unity使物体消失的三种方法 GameObject.Destroy(gameobjcet); //在下一帧破坏物体 gameObject.SetActive(false); //Unity2017新 ...

  4. 个人安装ss的一个记录

    在ubuntu16.04安装ss服务.由于lantern最近极其不稳定(我还花钱的qaq),经常断联以至于几乎废了,莫得办法,只好花钱搭一个了orz...呵,贫穷.... 安装shadowsocks ...

  5. POJ-3122(二分算法)

    //题意:这是一个分蛋糕的游戏, t个测试数据,输入n, f n代表的是n块蛋糕,蛋糕的高为1, f代表的是f个人朋友,然后输入每份蛋糕的半径 // 将n块蛋糕分成 f+1 份 每一份都是完成的一块蛋 ...

  6. Boss直聘邮件通知小脚本

    Boss 基于Python3的找工作利器--Boss直聘来消息邮件通知, 自动发送简历脚本,O(∩_∩)O~ 无聊写的,因为有时候觉得找工作心急如焚,想自动回复自动发简历啊有木有~~~ github地 ...

  7. 算法笔记(c++)--c++中碰到的一些用法

    算法笔记(c++)--c++中碰到的一些用法 toupper(xxx)可以变成大写; tolower(xx)小写 isalpha(xxx)判断是不是字母 isalnum(xx)判断是不是数字 abs( ...

  8. JavaScript 高级之面向对象

    1. 对象属性及方法 创建对象的方式 <script> //创建对象的方式一 var obj = {}; //创建对象的方式一 var obj = new Object(); </s ...

  9. Beta阶段中间产物

    空天猎功能说明书:https://git.coding.net/liusx0303/Plane.git 空天猎代码控制:https://coding.net/u/MR__Chen/p/SkyHunte ...

  10. Android开发第二阶段(3)

    今天:对闹钟代码的按钮事件进行了添加和修改.对监听器的相关应用也有了进一步的了解和深入. 明天:对主界面的代码的优化比如对按钮位置的调节等细节处理.