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

本节知识点:

1.malloc与free和new与delete的区别:
   a.malloc和free是 库函数,以 字节为单位申请堆内存
   b.new和delete是 关键字,以 类型为单位申请堆内存
   c.malloc和free是单纯的对内存进行申请与释放,不负责初始化,对于基本类型new关键字可以选择对内存进行初始化也可以不初始化
   d. 对于类类型new和delete还负责调用构造函数和析构函数的调用
示例代码:
#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关键字阻止编译器对构造函数的调用尝试,代码如下:
#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属性)。所以说,在满足上面三种情况下,就要使用静态成员变量!!!
示例代码:
#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属性变量
示例代码:
#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属性的变量,但是同样也不能回头,代码如下:
#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;
}








  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值