当前位置: 首页 > news >正文

宣城建设网站重庆装修论坛

宣城建设网站,重庆装修论坛,$post wordpress,免费制作自己的网页强制转换运算符 C 引入了四种不同的强制转换运算符以进行强制转换#xff1a; const_caststatic_castreinterpret_castdynamic_cast C语言强制类型转换缺点#xff1a; 主要是为了克服C语言强制类型转换的以下三个缺点。 没有从形式上体现转换功能和风险的不同。 例如 引入了四种不同的强制转换运算符以进行强制转换 const_caststatic_castreinterpret_castdynamic_cast C语言强制类型转换缺点 主要是为了克服C语言强制类型转换的以下三个缺点。 没有从形式上体现转换功能和风险的不同。 例如将int强制转换成double是没有风险的而将常量指针转换成非常常量指令 将基类指针转换成派生类指针都是高风险的而且后两者带来的风险不同即可能引发不同种类的错误C语言的强制类型转换形式对这些不同并不加以区分。 将多态基类指针转换成派生类指针时不检查安全性即无法判断转换后的指针是否确实指向一个派生类对象。难以在程序中寻找到底什么地方进行了强制类型转换。强制类型转换是引起程序运行是错误的一个原因因此在程序出错时可能就会想到是不是有那些强制类型转换出了问题。 const_cast 仅用于进行去除const属性的转换它也是四个强制类型转换运算符中唯一能够去除const属性的运算符。常量对象或者是基本数据类型不允许转化为非常常量对象只能通过指针和引用来修改 #include iostream #include stringint main(int argc, char const *argv[]) {const int n 5;const std::string s inception;// 错误std::string t const_caststd::string(s);// 错误int k const_castint(n);return 0; } 可以利用const_cast转换为同类型的非const引用或者指针 #include iostream #include stringint main(int argc, char const *argv[]) {const int n 5;// const_cast只针对指针引用,this指针int* k1 const_castint*(n);*k1 22;std::printf(n:%d k1:%d\n, n, *k1);int k2 const_castint(n);k2 33;std::printf(n:%d k1:%d, k2:%d\n, n, *k1, k2); }常成员函数中去除this指针的const属性 #include iostream #include string class CTest { public:CTest(): m_nTest(2){}// 常成员函数不能修改成员变量值void foo(int nTest) const{// m_nTest nTest; 错误const_castCTest*(this)-m_nTest nTest;} public:int m_nTest; };int main(int argc, char const *argv[]) {CTest t;t.foo(1);return 0; }static_cast 基于等价于隐式转换的一种转换运算符可使用于需要明确隐式转换的地方。可以用于低风险的转换。 整型和浮点型字符与整型转换运算符空指针转换为任何目标类型的指针 不可以用于风险高的转换 不同类型的指针之间的相互转换整型和指针之间的相互转换不同类型的引用之间的转换 #include iostream class CInt{ public:operator int(){return m_nInt;} public:int m_nInt; }; int main(int argc, char const *argv[]) {int n 5;float f 10.30f;// 本质上发生了隐式转换f n;std::printf(f:%d, n:%d\n, f, n);// 整型和浮点型f static_castfloat(n);std::printf(f:%d, n:%d\n, f, n);// 字符与整型char ch a;n static_castint(ch);std::printf(ch:%c, n:%d\n, ch, n);// void* 指针的转换void* p nullptr;int* pN static_castint*(p);// 转换运算符的方式CInt nObj;int k1 nObj;int k2 static_castint(nObj);return 0; } static_cast 用于基类与派生类的转换过程中但是没有运行时类型检查。 #include iostream class CFather{ public:CFather(){m_nTest 2;}virtual void foo(){std::cout CFather()::void foo() std::endl;} public:int m_nTest; }; class CSon: public CFather {virtual void foo(){std::cout CSon()::void foo() std::endl;} };int main(int argc, char const *argv[]) {CFather* pFather nullptr;CSon* pSon nullptr;// 父类转子类型不安全// pSon pFather; // 不能通过pSon static_castCSon*(pFather); // 能通过不安全没有提供运行时的检查// 子类转父类 安全pFather pSon;pFather static_castCFather*(pSon);return 0; }dynamic_cast 用于具有虚函数的基类与派生类之间的指针或引用的转换。 基类必须具备虚函数原因dynamic_cast是运行时类型检查需要运行时类型信息RTTI,而这个信息是存储与类的虚函数表关系紧密只有一个类定义了虚函数才会有虚函数表。运行时检查转型不成功则返回一个空指针非必要不要使用dynamic_cast,有额外的函数开销 常见的转换方式 基类指针或引用转派生类指针必须使用dynamic_cast派生类指针或引用转基类指针可以使用dynamic_cast,但是更推荐使用static_cast #include iostream class CFather{ public:CFather(){m_nTest 2;}virtual void foo(){std::cout CFather()::void foo() std::endl;} public:int m_nTest; }; class CSon: public CFather {virtual void foo(){std::cout CSon()::void foo() std::endl;} public:int m_nSon; };int main(int argc, char const *argv[]) {CFather f;CSon s;CFather* pFather f;CSon* pSon s;// 向上转换 子类装父类// pFather static_castCFather*(pSon);// 向下转换 父类转子类 (不安全)// pSon static_castCSon*(pFather);// pSon-m_nSon 2; // 越界// 检查出这种转换是不安全的// 运行时检测出被转换的指针的类型依赖RTTI// 有额外的开销一般而言只有向下转换是才必须使用pSon dynamic_castCSon*(pFather);if(pSon ! nullptr){pSon-m_nSon 2;}具有多态类型的向下转换是必须使用其余情况可以不使用return 0; } reinterpret_cast 用于进行各种 lambda表达式/匿名函数 lambda表达式 是一个源自阿隆佐.邱奇的术语。 lambda表达式是C11中最重要的性特性之一而lambda表达式实际上就是提供了一个类似匿名函数的特性而匿名函数则是需要一个函数但是又不想费力去命名一个函数情况下去使用的。这样的场景其实很多很多所以匿名函数几乎是现代编程语言的标配。 lambda表达式基础 lambda表达式的基础语法如下 [捕获列表](参数列表)mutable(可选)异常属性-返回类型{//函数体 } [caputrue](params)opt-ret{body;};lambda表达式以一对中括号开始。跟函数定义一样我们有参数列表跟正常的函数定义一样我们会有一个函数体里面会有return语句lambda表达式一般不需要说明返回值相当于auto,有特殊情况需要说明时则应使用箭头语法的方式每个lambda表达式都有一个全局唯一的类型要精确捕捉lambda表达式到一个变量中只能通过auto声明的方式 #include iostreamint main(int argc, char const *argv[]) {//lambda表达式就是匿名函数//[]捕获列表 ()参数列表 - 返回值int c [](int a, int b)-int{return a b;}(1, 2);std::printf(c:%d\n, c);auto f [](int a, int b)-int{return a b;};c f(4, 9);std::printf(c:%d\n, c);// 函数式编程 多线程并发c [](int a)-int{return [a](int b)-int{return a b;}(19);}(3);std::printf(c:%d\n, c);auto f1 [](int a){return [a](int b){return a b;};};c f1(11)(22);std::printf(c:%d\n, c);return 0; }mutable #include iostream int main(int argc, char const *argv[]) {int t 10;// 按值捕获auto f [t]() mutable{return t;};auto f1 [t]() mutable{return t;};std::cout f() std::endl;std::cout f1() std::endl;std::cout f() std::endl;std::cout f1() std::endl;std::cout t std::endl;return 0; }捕获列表 所谓捕获列表其实可以理解为参数的一种类型lambda表达式内部函数体在默认情况下是不能够使用函数体外的变量的这时候捕获列表可以起到传递外部数据的作用根据传递的行为捕获列表也分为以下几种 值捕获 与参数传值类似值捕获的前期是变量可以拷贝不同支持则在于被捕获的变量在lambda表达式被创建时拷贝而非调用时才拷贝 应用捕获 与引用传参类似引用捕获保存的是引用值会发生变化。 隐式捕获 手动书写捕获列表有时候是非常复杂的这种机械的工作可以交给编译器来处理这时候可以在捕获列表中写一个或向编译器声明采用引用或者值捕获 总结一下捕获提供了lambda表达式对外部值进行使用的功能捕获列表的最常用的四种形式可以是 [] 空捕获列表[name1, name2, …] 捕获一系列变量[] 引用捕获让编译器自行推导捕获列表[] 值捕获让编译器执行推导应用列表 #include iostreamint main(int argc, char const *argv[]) {int t 11;// t 33;// 按值捕获捕获的是声明匿名函数时捕获列表参数的值auto f [t]{std::cout t std::endl;};t 33;f();// 按引用捕获auto f2 [t](){std::cout t std::endl;t 99;};f2();std::cout t std::endl;int a 1;int b 2;// 捕获多个变量[a, b](){std::printf(ab%d\n, a b);}();// 按值捕获所有变量[](){std::printf(ab%d\n, a b);}();// 按引用捕获所有变量[](){a;b;}();return 0; }#include iostream #include vector #include algorithmint main(int argc, char const *argv[]) {std::vectorint v {1, 3, 4, 5, 6};for(int i 0; i v.size(); i){if(v[i] % 2 0){std::printf(偶数:%d\n, v[i]);}else{std::printf(奇数:%d\n, v[i]);}}std::printf(\n);std::for_each(v.begin(), v.end(), [](int n){if(n % 2 0){std::printf(偶数:%d\n, n);}else{std::printf(奇数:%d\n, n);}});return 0; } 函数对象包装器function与bind (1) std::function lambda 表达式的本质是一个函数对象当lambda表达式的捕获列表为空时lambda表达式还能够作为一个函数指针进行传递两种不同的调用方式一种是将lambda作为函数指针传递进行调用而另外一种则是直接调用lambda表达式在C11中统一了这些概念将能够被调用的对象的类型统一称之为可调用类型而这种类型便是通过std::function引入的。C11 std::function 是一种通用、多态的函数封装它的实例可以对任何可以调用的目标进行存储、复制和调用操作它也是对C中现有的可调用实体的一种类型安全的包裹相对来说函数指针的调用不是类型安全的换句话说就是函数的容器。当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理。 (2) std::bind/std::placeholder而std:bind则是用来绑定函数调用的参数的它解决的需求是我们有时候可能并不一定能够一次性获得调用某个函数的全部参数通过这个函数我们可以将部分调用参数提前绑定到函数身上作为一个新的对象然后在参数齐全后完成调用。 #include iostream #include functional #include algorithmclass CTest{ public:CTest(){}int MyTest(int n){std::printf(CTest n:%d\n, n);return n;}// 防函数int operator()(int n){std::printf(operator n:%d\n, n);return n;} }; int test(int n){std::printf(test n:%d\n, n);return n; } void test2(int a, int b, int c){std::cout a b c std::endl; } int main(int argc, char const *argv[]) {// 函数对象包装器// 为了函数提供了一种容器封装// 支持四种函数的封装// 1 普通函数// 2 匿名函数// 3 类成员函数// 4 防函数重载了运算符的函数test(1);// 普通函数std::functionint(int) f test;f(33);// 匿名函数std::functionint(int) f2 [](int n)-int{std::printf(f2 n:%d\n, n);return n;};f2(13);// 类成员函数std::functionint(CTest*, int) f3 CTest::MyTest;CTest t;f3(t, 66);// 防函数调用 重载运算符t(999);std::functionint(CTest*, int) f4 CTest::operator();f4(t, 888);// bind 机制auto f5 std::bind(test2, 1, 2, 4);f5();auto f6 std::bind(test2, std::placeholders::_2, std::placeholders::_1, 0);f6(5, 4);return 0; } 智能指针与RAII C 中最令人头疼的问题是强迫程序员对申请的资源文件、内存进行管理一不小心就会出现泄漏忘记对申请的资源进行释放的问题 auto prt new std::vectorint();C 的解决方法RAII 在传统C里我们只好使用new和delete去对资源进行释放而C11引入智能指针的概念使用了引用计数的想法让程序员不再需要关心手动释放内存。 解决思路 利用C中一个对象出了其作用域会被自动析构因此我们只需要在构造函数的时候申请空间而在析构函数在离开作用域时调用的时候释放空间这样就减轻了程序员在编码过程中考虑资源释放的问题这就是RAII。 RAII完整的英文是Resource Acquisition Initialization是C所有持有的资源管理方式。 有少量其他语言如果D、Ade和Rust也采纳了RAII但主流的变成语言中C是唯一一个依赖RAII来做资源管理的。RAII依托栈和析构函数来对所有的资源一一包括堆内存在内一一进行管理。对RAII的使用使得C不需要类似于Jave那样的垃圾收集方法也能有效地对内存进行管理。 具体而言C11的stl中为大家带来了3种智能指针正确合理的使用可以有效地帮助大家管理资源当然在C的使用智能指针没有像Javepython这种具备垃圾回收机制的语言那么舒适毕竟程序员还需要做一些额外的事情但是这远比传统的C或C更加优雅3种智能指针分别是 std::shared_ptr 强指针std::unique_ptrstd::weak_ptr 弱指针 在早期有一个auto_ptr这个四种指针在使用有区别 auto_ptr 有缺陷是过时的产物std::unique_ptr对auto_ptr的问题进行了修正。std::shared_ptr使用了引用计数但是会出现循环引用的问题需要配合后面的weak_ptr一起使用。 #include iostreamclass CTest{ public:CTest();~CTest(); private:int* m_pInt; };CTest::CTest(){m_pInt new int;std::printf(CTest finish \n); }CTest::~CTest(){if(m_pInt ! nullptr){delete m_pInt;}std::printf(~CTest finish \n); }int main(int argc, char const *argv[]){// 通过了new 在堆上分配了4个字节的空间// C 需要自己取管理堆内存的申请和释放int* p new int;CTest t;return 0; } 引用计数 要正确的理解智能指针首先必须理解引用计数技术。 深拷贝、浅拷贝的概念 深拷贝优缺点 优点每一个的对象哪怕是通过拷贝构造函数实例化的对象的指针都有指向的内存空间而不是共享所以在对象析构的时候就不存在重复释放或内存泄漏的问题了。缺点内存开销打 浅拷贝优缺点 优点通过拷贝构造函数实例化的对象的指针数据变量指向的共享内存空间因此内存开销较小。缺点对象析构的时候就可能会重复释放或造成内存泄漏。 鉴于深拷贝和浅拷贝的优缺点可采用引用计数技术即减小了内存开销又避免了堆的重复释放或内存泄漏问题。 举例说明 在深拷贝的情况下通过拷贝构造或者赋值构造的对象均各自包含自己的指针指向Helllo。但是显然这样比较浪费内存存在冗余那么下面的版本更好 #include iostream #include string #include string.hclass CStudent{ public:CStudent(const char* pszName);CStudent(CStudent obj);CStudent operator (CStudent obj);void release();void Show(){std::cout Show (int)m_pszName m_pszName std::endl;} private:char* m_pszName; };CStudent::CStudent(const char* pszName){m_pszName new char[256];strcpy(m_pszName, pszName); }CStudent::CStudent(CStudent obj){m_pszName obj.m_pszName; }CStudent CStudent::operator(CStudent obj){m_pszName obj.m_pszName;return *this; }void CStudent::release(){if(m_pszName ! nullptr){delete m_pszName;m_pszName NULL;} }int main(int argc, char const *argv[]){CStudent stu1(stu1);CStudent stu2(stu2);CStudent stu3 stu2;stu1.Show();stu2.Show();stu2.Show();stu2.release();stu3.Show();return 0; }这样代理的问题 但是这样同时存在问题一旦其中一个对象释放了资源那么所有的其他对象的资源也被释放了。解决方法增加一个变量记录资源使用的次数 #include iostream #include string #include string.hclass CStudent{ public:CStudent(const char* pszName);CStudent(CStudent obj);CStudent operator (CStudent obj);~CStudent();void release();void Show(){std::cout Show (int)m_pszName m_pszName std::endl;} private:char* m_pszName;//资源计数器, 当资源计数器减为0时那么表示该资源可以被重复的释放int * m_pCount; };CStudent::CStudent(const char* pszName){m_pszName new char[256];m_pCount new int;strcpy(m_pszName, pszName);*m_pCount 1; }CStudent::CStudent(CStudent obj){// 浅拷贝m_pszName obj.m_pszName;m_pCount obj.m_pCount;(*m_pCount); }CStudent CStudent::operator(CStudent obj){if(obj.m_pszName m_pszName){return *this;}if(--(*m_pCount) 0){delete m_pszName;m_pszName NULL;delete m_pCount;}m_pszName obj.m_pszName;m_pCount obj.m_pCount;(*m_pCount) ;return *this; } CStudent::~CStudent(){release(); }void CStudent::release(){if(m_pszName ! nullptr --*m_pCount 0){delete m_pszName;m_pszName NULL;delete m_pCount;m_pCount NULL;} }int main(int argc, char const *argv[]){CStudent stu1(stu1);CStudent stu2(stu2);CStudent stu3 stu2;stu1.Show();stu2.Show();stu3.Show();std::cout std::endl;stu2.release();stu3.Show();stu3.release();stu3.Show();return 0; }最后我们将该引用计数做一个简易的封装也就是把引用计数作为一个新的类来使用 #include iostream #include string #include string.hstruct RefValue{RefValue(const char* pszName);~RefValue();void AddRef();void Release();char* m_pszName;int m_nCount; };RefValue::RefValue(const char* pszName){m_pszName new char[strlen(pszName) 1];strcpy(m_pszName, pszName);m_nCount 1; }RefValue::~RefValue(){if(m_pszName! nullptr){delete m_pszName;m_pszName NULL;} }void RefValue::AddRef(){m_nCount; }void RefValue::Release(){if(--m_nCount 0){delete this;} }class CStudent{ public:CStudent(const char* pszName);CStudent(CStudent obj);CStudent operator (CStudent obj);~CStudent();void release();void Show(){if(m_pValue-m_nCount 0){std::cout Show (int)m_pValue-m_pszName m_pValue-m_pszName std::endl;}} private:RefValue* m_pValue; };CStudent::CStudent(const char* pszName){m_pValue new RefValue(pszName); }CStudent::CStudent(CStudent obj){// 浅拷贝m_pValue obj.m_pValue;m_pValue-AddRef(); }CStudent CStudent::operator(CStudent obj){if(obj.m_pValue m_pValue){return *this;}m_pValue-Release();m_pValue obj.m_pValue;m_pValue-AddRef();return *this; } CStudent::~CStudent(){release(); }void CStudent::release(){m_pValue-Release(); }int main(int argc, char const *argv[]){CStudent stu1(stu1);CStudent stu2(stu2);CStudent stu3 stu2;stu1.Show();stu2.Show();stu3.Show();std::cout std::endl;stu2.release();stu3.Show();stu3.release();stu3.Show();return 0; }问题 上面的做法能在一定程度上解决资源多次重复申请的浪费但是仍然存在两个核心的问题。 当前对其中某一个类对象中的资源进行了修改那么所有引用该资源的对象全部会被修改这显然是错误的。当前的计数器作用于Student类在使用时候需要强行加上引用计数类这样复用性不好使用不方便。 写时拷贝 问题如果共享资源中的值发生了变化那么其他使用该共享资源的值如何保持不变 解决思路使用引用计数时当发生共享资源值改变的时候需要对其资源进行重新的拷贝这样改变的拷贝的值而不影响原有的对象中的共享资源。 写时拷贝(COW copy on write),在所有需要改变值的地方重新分配内存。 #include iostream #include string #include string.hstruct RefValue{RefValue(const char* pszName);~RefValue();void AddRef();void Release();char* m_pszName;int m_nCount; };RefValue::RefValue(const char* pszName){m_pszName new char[strlen(pszName) 1];strcpy(m_pszName, pszName);m_nCount 1; }RefValue::~RefValue(){if(m_pszName! nullptr){delete m_pszName;m_pszName NULL;} }void RefValue::AddRef(){m_nCount; }void RefValue::Release(){if(--m_nCount 0){delete this;} }class CStudent{ public:CStudent(const char* pszName);CStudent(CStudent obj);CStudent operator (CStudent obj);~CStudent();void release();void Show(){if(m_pValue ! nullptr m_pValue-m_nCount 0){std::cout Show (int)m_pValue-m_pszName m_pValue-m_pszName std::endl;}}void SetName(const char* pszName); private:RefValue* m_pValue; };CStudent::CStudent(const char* pszName){m_pValue new RefValue(pszName); }CStudent::CStudent(CStudent obj){// 浅拷贝m_pValue obj.m_pValue;m_pValue-AddRef(); }CStudent CStudent::operator(CStudent obj){if(obj.m_pValue m_pValue){return *this;}m_pValue-Release();m_pValue obj.m_pValue;m_pValue-AddRef();return *this; } CStudent::~CStudent(){release(); }void CStudent::release(){m_pValue-Release(); }void CStudent::SetName(const char* pszName){m_pValue-Release();m_pValue new RefValue(pszName); }int main(int argc, char const *argv[]){CStudent stu1(stu1);CStudent stu2(stu2);CStudent stu3 stu2;stu1.Show();stu2.Show();stu3.Show();std::cout std::endl;stu2.SetName(stu222);stu1.Show();stu2.Show();stu3.Show();std::cout std::endl;stu2.release();stu3.Show();stu3.release();stu3.Show();return 0; } 智能指针的简易实现 前面我们学会了如何使用引用计数及写时拷贝这是理解智能指针必不可少的方法。但是在实际写代码中我们其实更倾向于让程序员对于资源的管理没有任何的感知也就是说最后让程序员只需要考虑资源的何时申请对于何时以及资源内部如何计数等问题统统交给编译器内部自己处理。 智能指针另外一点就是在使用上要像真正的指针一样可以支持取内容*指针访问成员-等操作因此就需要对这些运算符进行重载。 #include iostream// 智能指针 // 1. 用起来像指针 // 2. 会自己对资源进行释放 class CStudent{ public:CStudent(){};void test(){std::cout CStudent test std::endl;m_nSex 1;} private:char * m_pszBuf;int m_nSex; };// 创建一个类利用该类的构造和析构进出作用域自动被编译调用的机制 // 来解决资源自动释放的问题// 智能指针雏形 需要管理资源 class CSmartPtr{ public:// 一定要是一个堆对象CSmartPtr(CStudent* pObj){m_pObj pObj;}~CSmartPtr(){if(m_pObj ! nullptr){delete m_pObj;}}// 让对象用起来像一个指针 重载-运算符CStudent* operator -(){return m_pObj;}CStudent operator * (){return *m_pObj;}operator bool(){return m_pObj ! nullptr;}// 不允许号运算符重载拷贝构造// CSmartPtr operator (CSmartPtr) delete;// CSmartPtr(CSmartPtr) delete; // 使用拷贝移动// CSmartPtr operator (CSmartPtr obj){// if(m_pObj ! nullptr){// delete m_pObj;// }// m_pObj obj.m_pObj;// obj.m_pObj nullptr;// return *this;// } private:CStudent * m_pObj; }; int main(int argc, char const *argv[]){// 这里可以完成资源的自动释放 // 但是用起来不像一个指针CSmartPtr sp(new CStudent);// sp-m_pObj-test();sp-test();(*sp).test();if(sp){std::cout sp is true std::endl;}// 1. 不允许号运算符重载拷贝构造// 2. 使用拷贝移动auto_ptr 98// 3. 结合前面的引用计数以及写时拷贝 新的智能指针的写法// CSmartPtr sp2 sp;// CSmartPtr sp3(new CStudent);// sp3 sp;return 0; }智能指针的简易实现 #include iostreamclass CStudent{ public:CStudent(){};void test(){std::cout CStudent test std::endl;m_nSex 1;} private:char * m_pszBuf;int m_nSex; };class CrefCount{friend class CSmartPtr;CrefCount(CStudent* pStu){m_pObj pStu;m_nCount 1;}~CrefCount(){delete m_pObj;m_pObj NULL;}void AddRef(){m_nCount ;}void Release(){if(--m_nCount 0){// 这么写就表示自己一定要是一个堆对象delete this;}} private:CStudent* m_pObj;int m_nCount; };// 致命问题CSmartPtr中表示的类型是固定的是CStudent // 需要添加模版 class CSmartPtr{ public:CSmartPtr(){m_pRef NULL;}// 一定要是一个堆对象CSmartPtr(CStudent* pStu){m_pRef new CrefCount(pStu);}~CSmartPtr(){m_pRef-Release();}CSmartPtr(CSmartPtr obj){m_pRef obj.m_pRef;m_pRef-AddRef();}CSmartPtr operator(CSmartPtr obj){if(m_pRef obj.m_pRef){return *this;}m_pRef-AddRef();if(m_pRef ! NULL){m_pRef-Release();}m_pRef obj.m_pRef;return *this;}CStudent* operator-(){return m_pRef-m_pObj;}CStudent** operator(){return m_pRef-m_pObj;}CStudent operator*(){return *m_pRef-m_pObj;}operator CStudent*(){return m_pRef-m_pObj;} private:CrefCount* m_pRef; }; int main(int argc, char const *argv[]){CStudent* pStu new CStudent();CSmartPtr sp1(pStu);CSmartPtr sp2 sp1; // 拷贝构造// sp2 sp1; // 运算符重载return 0; }智能指针的简易实现 添加模版 #include iostreamclass CStudent{ public:CStudent(){};void test(){std::cout CStudent test std::endl;m_nSex 1;} private:char * m_pszBuf;int m_nSex; }; templatetypename T class CSmartPtr;templatetypename T class CrefCount{friend class CSmartPtrT; public:CrefCount(T* pStu){m_pObj pStu;m_nCount 1;}~CrefCount(){delete m_pObj;m_pObj NULL;}void AddRef(){m_nCount ;}void Release(){if(--m_nCount 0){// 这么写就表示自己一定要是一个堆对象delete this;}} private:T* m_pObj;int m_nCount; };// 致命问题CSmartPtr中表示的类型是固定的是CStudent // 需要添加模版 templatetypename T class CSmartPtr{ public:CSmartPtr(){m_pRef NULL;}// 一定要是一个堆对象CSmartPtr(T* pStu){m_pRef new CrefCountT(pStu);}~CSmartPtr(){m_pRef-Release();}CSmartPtr(CSmartPtr obj){m_pRef obj.m_pRef;m_pRef-AddRef();}CSmartPtr operator(CSmartPtr obj){if(m_pRef obj.m_pRef){return *this;}m_pRef-AddRef();if(m_pRef ! NULL){m_pRef-Release();}m_pRef obj.m_pRef;return *this;}T* operator-(){return m_pRef-m_pObj;}T** operator(){return m_pRef-m_pObj;}T operator*(){return *m_pRef-m_pObj;}operator T*(){return m_pRef-m_pObj;} private:CrefCountT* m_pRef; }; int main(int argc, char const *argv[]){CStudent* pStu new CStudent();// CrefCountCStudent ref(pStu);CSmartPtrCStudent sp1(pStu);CSmartPtrCStudent sp2(new CStudent);return 0; }
http://www.w-s-a.com/news/146634/

相关文章:

  • 济宁市建设工程质量监督站网站徐州网站优化推广
  • 北京网站设计多少钱php做商品网站
  • 能打开的网站你了解的彩票网站开发dadi163
  • 手机做网站价格优秀企业网站建设价格
  • 电商网站建设企业做网站的客户多吗
  • 有做思维图的网站吗西安建设市场诚信信息平台网站
  • 网站建设求职具备什么30岁学网站开发
  • 官方网站minecraft北京低价做网站
  • 网站建设报价兴田德润机械加工网络接单
  • 免费的推广网站安卓app制作平台
  • 长春火车站附近美食建设信用卡银行积分兑换商城网站
  • 网站提交网址如何备份wordpress网页
  • 龙腾盛世网站建设医院管理系统
  • 网站切换图片做背景怎么写外贸营销邮件主题一般怎么写
  • 基于html5的网站开发wordpress主题工具
  • php网站开发的成功经历公司网站现状
  • 软件发布网站源码中国企业公示信息网
  • flash 的网站网站型销售怎么做
  • 营销型网站单页网站的域名和密码
  • 建网站保定seo自动发布外链工具
  • 做公众号关注网站做课件用这15大网站
  • 怎么制作公司自己网站店铺设计软件手机版
  • 深圳网站关键词优化公司哪家好怎么选择锦州网站建设
  • 标准网站优势项目合作网站
  • 无人机东莞网站建设wordpress站群管理破解版
  • 深圳企业官网网站建设教育培训学校
  • 医疗网站建设及优化西安网站建设开发公司
  • 网站建设详细流程ydg wordpress theme
  • 湖北黄石域名注册网站建设编程网站项目做哪个比较好
  • 旺道网站排名优化咸阳建设网站