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



相关文章
|
12天前
|
存储 C++ 容器
C++STL(标准模板库)处理学习应用案例
【4月更文挑战第8天】使用C++ STL,通过`std:vector`存储整数数组 `{5, 3, 1, 4, 2}`,然后利用`std::sort`进行排序,输出排序后序列:`std:vector<int> numbers; numbers = {5, 3, 1, 4, 2}; std:sort(numbers.begin(), numbers.end()); for (int number : numbers) { std::cout << number << " "; }`
17 2
|
18天前
|
开发框架 Linux C语言
C、C++、boost、Qt在嵌入式系统开发中的使用
C、C++、boost、Qt在嵌入式系统开发中的使用
29 1
|
8天前
|
编译器 C语言 C++
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
16 0
|
8天前
|
存储 算法 C++
【C++初阶】STL详解(九) priority_queue的使用与模拟实现
【C++初阶】STL详解(九) priority_queue的使用与模拟实现
20 0
|
8天前
|
存储 算法 编译器
【C++初阶】STL详解(三)vector的介绍与使用
【C++初阶】STL详解(三)vector的介绍与使用
25 0
|
8天前
|
存储 编译器 C++
【C++初阶】STL详解(四)vector的模拟实现
【C++初阶】STL详解(四)vector的模拟实现
38 1
|
12天前
|
存储 算法 C语言
【C++初阶】8. STL初阶 + String类
【C++初阶】8. STL初阶 + String类
48 1
|
18天前
|
存储 缓存 C++
C++链表常用的函数编写(增查删改)内附完整程序
C++链表常用的函数编写(增查删改)内附完整程序
|
20天前
|
存储 安全 编译器
【C++】类的六大默认成员函数及其特性(万字详解)
【C++】类的六大默认成员函数及其特性(万字详解)
35 3
|
23天前
|
算法 C++ 容器
【C++练级之路】【Lv.10】【STL】priority_queue类和反向迭代器的模拟实现
【C++练级之路】【Lv.10】【STL】priority_queue类和反向迭代器的模拟实现