首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

c++学习笔记(10.专题二经典问题解析)

c++学习笔记(10.专题二经典问题解析)

本节知识点:1.malloc与free和new与delete的区别:   a.malloc和free是库函数,以字节为单位申请堆内存
   b.new和delete是关键字,以类型为单位申请堆内存
   c.malloc和free是单纯的对内存进行申请与释放,不负责初始化,对于基本类型new关键字可以选择对内存进行初始化也可以不初始化
   d.对于类类型new和delete还负责调用构造函数和析构函数的调用
示例代码:
[cpp] view plaincopy


  • #include <iostream>
  • #include <malloc.h>

  • using
    namespace std;  
  • class test  
  • {  
  • private:  
  •     int a;  
  •     int b;  
  • public:  
  •     int c;  
  •     test(int a, int b)  
  •     {  
  •         this->a = a;  
  •         this->b = b;  
  •         c = 9;  
  •         cout << "a is "<< a <<endl;  
  •         cout << "b is "<< b <<endl;  
  •     }  
  • };  
  • int  main()  
  • {  
  •     test *p = new test(1,2); //当使用new创建一个类的对象的时候  调用构造函数
  •     test *q = reinterpret_cast <test*> (malloc(sizeof(test))); //使用malloc 不调用构造函数
  •     cout << "q is " << q->c <<endl;  
  •     cout << "c is " << p->c <<endl;      
  •     return 0;  
  • }   




2.编译器对构造函数的调用:   a.一般类给对象进行初始化的方式有三种,test t1(5);    test t2 = 5;     test t3  = test(5);  在现代编译器中他们三个是等效的,但是从编译器内部来看是有区别的   b.test t1(5)是最简单直接的,他强制编译器直接调用test类的构造函数(explicit无效)。test t2 = 5有四个步骤,第一,默认情况下,字面量5的类型为int,因此5无法直接用于初始化test对象,第二,但是编译器在默认情况下可以自动调用构造函数(explicit有效),第三,于是编译器尝试调用test(int)生成一个临时对象,第四,最后调用拷贝构造函数test(const test& obj) 用临时对象给t2进行初始化(explicit有效)。test t3 = test(5) 则是首先,手动调用test(int)构造函数(explicit无效),最后,编译器默认自动调用拷贝构造函数(explicit有效)
   c.c++编译器会尝试各种手段让程序通过编译:
      方式一:尽力匹配重载函数
      方式二:尽力使用函数的默认参数
      方式三:尽力尝试调用构造函数进行类型转换
   d.利用explicit关键字阻止编译器对构造函数的调用尝试,代码如下:
[cpp] view plaincopy


  • #include <iostream>
  • using
    namespace std;  
  • class test  
  • {  
  • private:  
  •     int a;  
  • public:   
  •     //explicit
  •     test(int c)  
  •     {  
  •         cout << "test()" <<endl;  
  •     }  
  •     //explicit
  •     test(const test& p)  
  •     {  
  •         cout << "test(const test& p)" <<endl;  
  •     }  
  •     ~test()  
  •     {  
  •         cout << "~test()" <<endl;  
  •     }  
  • };  
  • int main()  
  • {  
  •     test a1(8);   //阻止谁都没关系  因为这是最根本对 对象的初始化
  •     test a2 = 8; //阻止构造函数 或者 阻止拷贝构造函数 都会造成这条语句的编译不过
  •     test a3 = test(8);  //阻止拷贝构造函数会造成这条语句的编译不过 因为构造函数是手动调用的
  •     return 0;  
  • }  

   e.还有一个小问题,就是对于test t2  =  5 的这种方式,只能用于有test(int a)这样的构造函数的对象进行初始化。如果构造函数为test (int a, int b)这样,test t2 = (5, 4)是会编译出错的!!!


3.单例模式:
   a.单例模式是类的静态成员的一个很好的应用,单例模式适用于一个类只允许产生一个对象的情况
   b.分析下单例模式:既然这个类仅仅只能产生一个对象的话,所以这个类的构造函数就应该是private属性的,创建这类就不能是使用test t1(5)这样的语句了,就只能使用函数(有两种,一种是静态成员函数另一种是使用全局函数,这里面那个返回地址的变量也得是全局变量了 最好不要使用,因为这样就破坏了类的封装),成员函数不可以的原因是:没有对象无法调用成员函数。函数中使用new关键字,new这个类,然后将new出来的新地址返回,这里面就需要一个static的静态成员变量来保存这个地址,在这种情况下必须使用静态成员变量,因为这个变量即要在类中使用(应该定义在类的前面或类中),而且这个变量的类型还是这个类的类型或指针类型(应该定义在类的后面或类中)要返回给其他函数使用这个变量应该是静态类型的(static属性)。所以说,在满足上面三种情况下,就要使用静态成员变量!!!
示例代码:
[cpp] view plaincopy


  • #include <iostream>
  • using
    namespace std;  

  • class test  
  • {  
  • private:  
  •     static test* tp;  
  •     test()  
  •     {  

  •     }  
  • public:   
  •     static test* creat()  
  •     {  
  •         if(NULL == tp)  
  •         {  
  •             cout << "hello" <<endl;  
  •             tp = new test;  
  •         }  
  •         return tp;  
  •     }  

  • };  
  • test* test::tp = NULL;  
  • int main()  
  • {  
  •     test* only = test::creat();  
  •     test* only1 = test::creat();  
  •     return 0;  
  • }  




4.函数对象的实现:   a.无状态函数:函数的调用只与实参值相关
   b.状态函数:函数的调用结果不仅与实参值相关还与之前的函数调用有关,就是有记忆功能的函数,其实就是利用static属性变量
示例代码:
[cpp] view plaincopy


  • #include <cstdlib>
  • #include <iostream>

  • using
    namespace std;  

  • int fib1(int i)  
  • {  
  •     int a1 = 0;  
  •     int a2 = 1;  
  •     int ret = a2;  

  •     while( i > 1)  
  •     {  
  •         ret = a2 + a1;  
  •         a1 = a2;  
  •         a2 = ret;  
  •         i--;  
  •     }  

  •     return ret;  
  • }  

  • int fib2()  
  • {  
  •     static
    int a1 = 0;  
  •     static
    int a2 = 1;  

  •     int ret = a2;  
  •     int t = a2;  

  •     a2 = a2 + a1;  
  •     a1 = t;  

  •     return ret;  
  • }  

  • int main(int argc, char *argv[])  
  • {  
  •     for(int i=1; i<=10; i++)  
  •     {  
  •         cout<<fib1(i)<<endl;  
  •     }  

  •     for(int i=1; i<=10; i++)  
  •     {  
  •         cout<<fib2()<<endl;  
  •     }  

  •     return 0;  
  • }  




注意:第一,fib1是以无状态函数的方式实现的,求解数列每一项时都会做重复的循环,时间复杂度为O(n)
           第二,fib2是以状态函数的方式实现的,每调用一次就可以得到数列当前项的值,时间复杂度为O(1),但是无法从头再来
    c.函数对象的实现:其实就是利用对象来模拟有状态函数,利用对象中的成员变量来代替static属性的变量,但是同样也不能回头,代码如下:
[cpp] view plaincopy


  • #include <cstdlib>
  • #include <iostream>

  • using
    namespace std;  

  • int fib1(int i)  
  • {  
  •     int a1 = 0;  
  •     int a2 = 1;  
  •     int ret = a2;  

  •     while( i > 1)  
  •     {  
  •         ret = a2 + a1;  
  •         a1 = a2;  
  •         a2 = ret;  
  •         i--;  
  •     }  

  •     return ret;  
  • }  

  • int fib2()  
  • {  
  •     static
    int a1 = 0;  
  •     static
    int a2 = 1;  

  •     int ret = a2;  
  •     int t = a2;  

  •     a2 = a2 + a1;  
  •     a1 = t;  

  •     return ret;  
  • }  

  • class Fib  
  • {  
  • private:  
  •     int a1;  
  •     int a2;  
  • public:  
  •     Fib()  
  •     {  
  •         a1 = 0;  
  •         a2 = 1;  
  •     }  

  •     int operator() ()  
  •     {  
  •         int ret = a2;  
  •         int t = a2;  

  •         a2 = a2 + a1;  
  •         a1 = t;  

  •         return ret;  
  •     }  
  • };  

  • int main(int argc, char *argv[])  
  • {  
  •     cout<<"int fib1(int i)"<<endl;  

  •     for(int i=1; i<=10; i++)  
  •     {  
  •         cout<<fib1(i)<<endl;  
  •     }  

  •     cout<<endl;  

  •     cout<<"int fib2()"<<endl;  

  •     for(int i=1; i<=10; i++)  
  •     {  
  •         cout<<fib2()<<endl;  
  •     }  

  •     cout<<endl;  

  •     Fib fib;  

  •     cout<<"Fib fib;"<<endl;  

  •     for(int i=1; i<=10; i++)  
  •     {  
  •         cout<<fib()<<endl;  
  •     }  

  •     cout<<endl;  

  •     return 0;  
  • }  


返回列表