C++ STL开发温习与总结(三): 3.C++函数技术

简介: C++ STL开发温习与总结(三): 3.C++函数技术

若该文为原创文章,转载请注明原文出处

本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78072366

长期持续带来更多项目与技术分享,咨询请加QQ:21497936、微信:yangsir198808

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...

其他(编程相关)

上一篇:C++ STL开发温习与总结(二): 2.C++存储技术

下一篇:C++ STL开发温习与总结(四): 4.C++面向对象机制的实现

 

前言

      几乎所有的C++类都有一个或多个构造函数,一个析构函数和一个赋值操作符。

      对于任何一个类A,如果不想编写上述函数,C++编译器将自动为A产生4个缺省的函数,如下:

       A(void);// 缺省的无参数构造函数
       A(constA &a); // 缺省的拷贝构造函数
       ~A(void);//缺省的析构函数
       A &operate = (const A & a); // 缺省的赋值函数

 

1 类的构造函数、析构函数与赋值函数

      C++提供了更好的机制来增强程序的安全性。C++编译器具有严格的类型安全检查功能,它几乎能找出程序中所有的语法问题。

      根据经验,不少难以察觉的程序是由于变量没有被正确初始化或清楚造成的,而初始化和清楚工作很容易被人遗忘。C++很好的考虑了这个问题,把对象的初始化工作放在构造函数中,把清除工作放在析构函数中。

1-1 构造函数技术

      构造函数除了具有普通成员函数的所有特性外还有下面的几个特殊点:

l  构造函数名必须和类名相同,且不得声明任何返回值类型;

l  构造函数可以用形参形式带进各成员数据的初值,也可以重载多个构造函数;

l  构造函数特殊的功能:测算本类对象所需的静态内存容量并动态占用该容量的内存资源;

l  构造函数并非没有返回值,它所返回的值是一个指向其所定义对象的首地址的指针,但不能被传递;

l  若直接引用声明于public区中的构造函数将导致该类的一个新对象生成,但若没有相关的句柄与之来年系,则无法与对象进行通信联系;

l  生命与private区中的构造函数只能通过定义在public区中的函数引用;

l  如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数;

l  类的const常量只能在初始化表里被初始化,它不能在函数体内用赋值的方式来初始化;

l  类的数据成员的初始化可以采用初始化表或函数体内赋值两种方式。非内部数据类型的成员对象应当采用第一种方式初始化,以获取更高的效率。

缺省构造使用:

Demo h;

非缺省构造使用:

 

 

Demoh(0);// 或者写成Demoh=4;

追求更高的效率

B::B(const A &a) : m_a(a) { …}

同样的功能,下面先暗地里创建m_a,再调类A的赋值函数

B::B(const A &a) { m_a = a; …};

1-2 析构函数技术

    析构函数由定义类对象的分程序在其运行结束之前被自动地引用。与构造函数一样,析构函数也不得声明任何的返回类值型、不得带有任何参数且不得重载,也不能被置于private区,有且仅有一个析构函数。

      析构函数除了可以(用delete)释放在构造函数中指明占用的内存外,还要释放整个对象的成员等所占用的内存,这些只是不必写进去。

      如果一个基类的析构函数被说明未虚析构函数,则它的派生类中的析构函数也是虚析构函数,不管它是否引用了关键字virtual进行说明。

1-3 构造和析构的次序

      构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对像的构造函数。      析构则严格按照与构造相反的次数执行,该次序是惟一的,否则编译器将无法自动执行析构过程。

    一个特别的现象是:成员对象初始化的次序完全不受它们在初始化表中次序的影响,只由成员对象在类中声明的次序状态决定,这是因为类的声明是惟一的,而类的构造函数可以有多个,因此会有多个不同次序的初始化表。

1-4 成员初始化表设计

      C++语言在原有赋值方式的基础上,增加了一个成为成员初始化表的特别手段来简化这种初始化过程,由于此种手段是编译阶段由编译器将要初始化的成员数据与参数建立了对应联系,所以用此法的系统在运行阶段的开销较之其他方法都要小得多

      成员初始化表放在构造函数名与构造函数体之间,用冒号与函数名部分相分隔,每个表的格式为:

      类中成员名(初值),类中成员名(初值)

ST(unsignedint y, unsigned int, unsigned int d): yy(y), mm(m), dd(d)

      C++语言中只有const和引用类型是要在编译时就要指明其初值。由于定义在类中的成员都是抽象的数据结构描述,不可能分配内存单元,因此在对构造函数进行编译的阶段也就不可能完成赋初值的操作了。为了解决这一矛盾,C++语言只有借助于类对象“成员初始化表”的描述去将要赋初值的成员名及初值预先声明,待执行时产生对象(即分配了内存单元)后再补做上述的赋初值操作。所以从某种意义上讲,成员初始化表是特意为这两种数据成员准备的也不为过,由此切记成员初始化表不可写在声明语句上。

1-5 类中的const成员函数的特性

* 防止本函数误写参数变量

返回值类型函数名(const 参数, const 参数, …)

* 防止本函数误写类对象内全部的变量的

返回值类型函数名(参数表) const;

* 防止其他函数误写返回地址或引用的

const 返回值类型函数名(参数表)

1-6 拷贝构造函数与赋值函数

      由于并非所有的对象都会使用拷贝函数和赋值函数,程序员可能对这两个函数有些轻视(确实如此)。如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。

      以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。现在a赋值给b,缺省赋值函数的“位拷贝”意味着执行b.m_data=a.m_data。这将造成3个错误:

      一是b.m_data原来的内存没有被释放,造成内存泄漏;

      二是b.m_data和a.m_data指向同一块内存,a或b任何一方变动都将影响另一方;

      三是在对象被析构时,m_data被释放了两次。

 

2 在派生类中实现类的基本函数

      基类的构造函数、析构函数、赋值函数都不能被派生类继承。如果类之间存在继承关系,在编写上述基本函数时应注意以下事项:

n  派生类的构造函数应在其初始化表里调用积累的构造函数

n  基类与派生类的析构函数应为虚(即加virtual关键字)。

3 内联函数技术

      C++语言支持函数内联,其目的是为了提高函数的执行效率(速率)。在C程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但使用起来湘函数。与处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的CALL调用、返回参数、执行return等过程,从而提高了速率。使用宏代码最大的缺点是容易出错,与处理器在复制宏代码时常常产生意想不到的边际效应。例如:

#defineMAX(a,b)  (a)>(b)?(a):(b)

可改写避免边际效应

#defineMAX(a,b)  ((a)>(b)?(a):(b))

      函数调用会带来降低效率的问题,因为调用函数实际上将程序执行顺序转移到函数所存放的内存中的某个地址,将函数的程序内容执行完后,在返回到调用该函数前程序语句所在位置。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后要先恢复现场,并按原来保存地址继续执行。因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来说,解决其效率问题更为重要。引入内联实际上是为了解决这一问题。

*  在内联函数不允许用循环语句和开关语句

*  内联函数的定义必须出现在内联函数第一次被调用之前。

 

4友元函数技术

      只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。

      为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明是前面加关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了封装性和隐藏性,使得非成员函数可以访问类的私有成员。

      友元可以是一个函数,也可以是一个类。

 

上一篇:C++ STL开发温习与总结(二): 2.C++存储技术

下一篇:C++ STL开发温习与总结(四): 4.C++面向对象机制的实现

 

若该文为原创文章,转载请注明原文出处

本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78072366



相关文章
|
11天前
|
IDE 开发工具 C语言
C++一分钟之-嵌入式编程与裸机开发
通过这些内容的详细介绍和实例解析,希望能帮助您深入理解C++在嵌入式编程与裸机开发中的应用,提高开发效率和代码质量。
31 13
|
15天前
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
19 1
|
28天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
47 7
|
2月前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
82 4
|
2月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
88 5
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
69 2
|
2月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
70 0
|
1月前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
39 0
WK
|
2月前
|
机器学习/深度学习 人工智能 算法
那C++适合开发哪些项目
C++ 是一种功能强大、应用广泛的编程语言,适合开发多种类型的项目。它在游戏开发、操作系统、嵌入式系统、科学计算、金融、图形图像处理、数据库管理、网络通信、人工智能、虚拟现实、航空航天等领域都有广泛应用。C++ 以其高性能、内存管理和跨平台兼容性等优势,成为众多开发者的选择。
WK
121 1
|
3月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。