经典问题总结(二)

mallocfreenewdelete有什么区别?

malloc free 是库函数,以字节为单位申请堆内存;
new delete 是关键字,以类型为单位申请堆内存;
malloc free 单纯的对内存进行申请与释放;
对于基本类型 new 关键字会对内存进行初始化;
对于类类型 new delete 还负责构造函数和析构函数的调用;

#include <cstdlib>
#include <iostream>
using namespace std;
class Test//定义一个类
{
private:
    int i;
public:
    Test()//构造函数(本质就是初始化)
    {
        cout<<"Test()"<<endl;
        i = 0;
    }   
    Test(int i)
    {
        cout<<"Test(int i)"<<endl;
        this->i = i;
    }    
    ~Test()//析构函数(在类的对象消失之前进行清理,包含动态内存释放,文件关闭,资源释放等等)
    {
        cout<<"~Test"<<endl;
    }    
    int getI()
    {
        return i;
    }
};
void func()
{
    //对基本类型,malloc只是能够单纯申请空间,而new关键字还可以初始化
    int* p = reinterpret_cast<int*>(malloc(sizeof(int)));//通过malloc函数向堆内存申请4个字节空间,malloc函数返回值类型void*,因此需要强制类型转换
    int* q = new int(10);//通过new关键字向堆内存申请4个空间    
    *p = 5;
    //*q = 10;    
    cout<<*p<<" "<<*q<<endl;   
    free(p);//释放
    delete q;
    //对类类型,new关键字可调用构造函数
    Test* op = reinterpret_cast<Test*>(malloc(sizeof(Test)));
    Test* oq = new Test;  
    cout<<op->getI()<<" "<<oq->getI()<<endl;  
    free(op);//释放
    delete oq;//可调用析构函数
}//内存的关键字使用注意配对!!!
int main(int argc, char *argv[])
{
    func();  
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
编译器对构造函数的调用:

C++ 编译器会尝试各种手段尝试让程序通过编译:
方式一:尽力匹配重载函数;
方式二:尽力使用函数的默认参数;
方式三:尽力尝试调用构造函数进行类型转换;



“剥夺”编译器对构造函数的调用尝试:
C++ 提供了 explicit 关键字用于阻止编译器对构造函数的调用尝试;
#include <cstdlib>
#include <iostream>//在现代c++编译器看来,下面这三种初始化的方式是等价的,但是效率高低不同
//在古代,这三种初始化方式在c++中看来是不同的语义,本质上是不同的,现代c++编译器优化了此问题
using namespace std;
class Test
{
public:
    Test(int i)
    {
        cout<<"Test(int i)"<<endl;
    }    
    Test(const Test& obj)//拷贝构造函数
    {
        cout<<"Test(const Test& obj)"<<endl;
    }    
    ~Test()
    {
        cout<<"~Test"<<endl;
    }
};
void func()
{
    Test t1(5);//c++最标准的初始化方式,构造方式
    Test t2 = 5;
    Test t3 = Test(5);
}
int main(int argc, char *argv[])
{
    func();
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

类的静态成员能用来干嘛呢?

对象数目控制:单例模式的实现

#include <cstdlib>//单例模式的实现
#include <iostream>//静态成员函数和静态成员变量可以帮助我们实现一些在面向对象过程中很多高端的方法,
//设计模式中的很多东西都是需要借助于静态成员函数和静态成员变量来完成的
using namespace std;
class Singleton
{
private:
    static Singleton* cInstance;//静态指针singleton
    Singleton()//构造函数声明为私有的
    {
    }
public:
    static Singleton* GetInstance()//静态成员函数
    {
        if( cInstance == NULL )
        {
            cout<<"new Singleton()"<<endl;
            cInstance = new Singleton();//此处调用是合法的
        }
        return cInstance;
    }
    void print()
    {
        cout<<"I'm Singleton!"<<endl;
    }
};
Singleton* Singleton::cInstance = NULL;

void func()
{
    Singleton* s = Singleton::GetInstance();//通过GetInstance()得到一个对象,此对象和cInstance得到对象是一致的
    Singleton* s1 = Singleton::GetInstance();
    Singleton* s2 = Singleton::GetInstance();
    cout<<s<<" "<<s1<<" "<<s2<<endl;
    s->print();
}
int main(int argc, char *argv[])
{
    func();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}


无状态函数: 函数的调用结果只与实参值相关;
状态函数:函数的调用结果不仅与实参值相关还与之前的函数调用有关;

#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;
    }
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

两中实现的问题:
fib1 是以无状态函数的方式实现的,求解数列每一项时都会做重复的循环,时间复杂度为 O(n)
fib2 是以状态函数的方式实现的,每调用一次就可以得到数列当前项的值,时间复杂度为 O(1) 但是无法从头再来

函数对象的实现:
#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() ()//高效,也可重头再来,函数对象解决了状态函数无法重头再来,这就是c++操作符重载的魅力所在!!!
    {
        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;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值