c++的一些细节(四)

1、匿名对象

        c++提供了以下写法

class Date 
{
public:
	Date(int year = 0, int month = 1, int day = 1)
		:_year(year), _month(month), _day(day)
	{}
	ostream& operator<<(ostream& out)
	{
		out << _year << " " << _month << " " << _day << endl;
		return out;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date();
	return 0;
}

        在Date();语句就是创建了一个匿名对象,他是一个合法的对象,遵循对象的构造和析构原则,可以调用对象的成员函数以及访问成员变量。注意这个匿名对象的生命周期只在这一行,离开这一行自动销毁,也就是说对象的创建、成员的访问、对象的析构在这一行完成。

2、静态变量和全局变量的异同点

        静态变量和全局变量都存储在静态区或者说数据段。二者的生命周期为整个源程序,不过全局变量的定义发生在main函数外部,静态变量的定义可以发生在任何地方(main函数内部,其他函数内部,类内部等)。静态变量的访问受其作用域的限制,函数体内定义的静态变量无法在函数外访问,类内定义的静态变量的访问需受到访问限定符的限制。

3、动态内存开辟

        在c中我们动态内存开辟用的是malloc、calloc、realloc三个函数,作用分别是,以字节为单位,开辟空间、开辟空间并初始化为0、重新开辟空间。

        c++中我们有用于开辟空间的新写法new,以及释放空间的写法delete,可以在开辟是进行内置类型的初始化,如果是自定义类型,则会调用构造函数,delete会调用析构函数。

        注意,对于自定义类型,new出一块空间时,会调用构造函数,但这一整套行为不等于实例化出一个对象,实例化出的对象在出了作用域后会自动调用析构函数,而new出一块空间,不会析构他。

4、operate new和operate delete

        new和delete是用于用户动态内存申请的操作符,operate new和operate delete是系统提供的全局函数。new在底层调用operate new来申请内存的,delete在底层调用operate delete来释放内存。

        operate new:该函数实际通过malloc来进行内存申请,如果申请成功则返回首地址,失败则抛异常。

        operate delete:实际是通过free来进行内存释放的。

        可以得出结论,new和delete多了构造和析构的功能,本质上是在operate new和operate delete上做了一些扩展,进行封装。而operate new多了抛异常的功能,是对malloc和free的封装。三者是层层递进的关系,底层还是c语言最原始的malloc和free。

5、对已存在的空间调用构造函数初始化

        经过对operate new和operate delete的了解,我们知道,我们的new和delete在执行时先后进行两种操作。(1)new,先调用operate new开辟空间,再调用对象的构造函数。(2)delete,先调用对象的析构函数,再调用operate delete释放空间。

        现在如果用户想要将这两种操作分开进行怎么操作?比如,我们开辟对象的空间时不进行初始化,再后面的语句中再进行初始化,独立进行两种操作。

        c++中提供了对已经存在的一块空间进行初始化的写法,如下。

class A
{
public:
    A(int a = 0)
        :_a(a)
    {}
private:
    int _a;
};

int main()
{
    A* p = (A*)operator new(sizeof(A));
    new(p)A(10);
    return 0;
}

        在main中,第一句是开辟空间而不初始化,第二句是对已存在的空间初始化,二者分开进行。

6、malloc/free和new/delete之间的区别。

        (1)malloc和free是函数,new和delete是操作符。(2)malloc申请的空间不会初始化,new可以初始化。(3)malloc申请空间时,需要手动计算空间大小并传入,而new只需在后面跟上空间的类型即可。(4)malloc的返回值是void*,在使用时必须强转,而new不需要,new后面跟的就是空间类型。(5)malloc申请失败时返回NULL,使用时必须判定是否为空,而new不需要,new在申请时需要捕获异常。(6)对于自定义类型,使用new和delete会调用构造函数和析构函数,而malloc和free不会。

7、模板

(1)函数模板

            设想一种场景,你需要完成int之间,float之间,char之间的变量数值交换,需要写三个函数吗?c++提供了提高编写效率的函数模板,template<class >或者template<typename >,具体写法如下。

        函数模板代表了一个函数家族,该模板与函数无关,在使用时根据实参类型实例化出特定的函数。

template<class T>
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

int main()
{
    int a1 = 1, b1 = 2;
    Swap(a1, b1);
    float a2 = 1.1, b2 = 2.2;
    Swap(a2, b2);
    char a3 = 'a', b3 = 'b';
    Swap(a3, b3);
    return 0;
}

        我们在调试时会发现,三次swap调用都进入了上面的同一个函数模板,那么三次调用的是同一个函数吗?肯定不是的,参数类型都不一样肯定不是同一个函数。在我们代码的编译阶段,准确地说是预处理阶段(编译阶段已经在检查语法了),编译器会根据调用函数时的传参实例化出不同的函数。这些函数都是实实在在存在的,只是不是我们自己写,而是编译器实例化的。

        值得注意的是,是可以同时定义一个函数和声明一个同名的函数模板的。如下。

int Add(int left, int right)
{
	return left + right;
}

template<class T>
T Add(T left, T right)
{
	return left + right;
}
int main()
{
	Add(1, 2);
	Add<int>(1, 2);
	return 0;
}

        在这种情况下,编译器会优先调用已经定义的函数,即main中的第一个Add调用的是上面已经定义的Add,如果想要调用以模板生成的Add需要在函数名后指定模板参数的类型,这种行为称为模板的特化。

(2)类模板

        与上面类似,如果我们想要实现顺序表或者链表,难道要写针对不同类型(char,int)的相同逻辑的多份代码吗?c++同样提供了我们用于泛型编程的类模板。用法如下。

template<class T>
class vector
{
public:
	vector()
		:_a(nullptr), _capacity(0), _size(0)
	{}
	~vector()
	{
		delete[] _a;
		_a = nullptr;
		_capacity = _size = 0;
	}
	void push_back(const T&);
private:
	T* _a;
	size_t _capacity;
	size_t _size;
};

        与函数模板类似,类模板一样是在实例化时编译器推出确定的类型,进行声明。

        需要注意的一点,在类模板中声明一个函数,在类模板外实现时,写法如下。

template<class T>
class vector
{
public:
	vector()
		:_a(nullptr), _capacity(0), _size(0)
	{}
	~vector()
	{
		delete[] _a;
		_a = nullptr;
		_capacity = _size = 0;
	}
	void push_back(const T&);
private:
	T* _a;
	size_t _capacity;
	size_t _size;
};

template<class T>
void vector<T>::push_back(const T&)
{}

        可以理解为,类模板中的成员函数,同样是函数模板,在类外定义时是要在头一行加上模板的标准格式“template<class T>”,在函数名前还需要加上类域限定符,因为类型名不是vector而是vector<T>,所以具体写法为void vector<T>::push_back(const T&)。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值