嵌入式基础之----C++


一:构造与析构

为什么需要构造函数:因为类是一个集合的东西,里面包含了很多的数据。当定义了一个类的具体对象时,初始化就显得是必须的了。如果是全局的对象,那么其数据会被初始化为零,但往往不会去定义全局的对象。所以就迫切的需要一个成员函数专门进行初始化的工作,这就是构造函数,它以人们预期的方式对对象进行初始化。

如果一个类中没有显示的定义构造函数,那么系统会提供一个默认的构造函数,它没有参数,什么事情也不做。一旦显示的定义了构造函数(无论是否是默认构造函数),那么编译器都不会在给你提供默认构造函数。

声明构造函数的方法是: 类名(参数列表);

定义构造函数的方法是:类名::类名(参数列表){ 初始化实现 }

构造函数的分类:默认构造函数(没有参数,注意在使用时不能加小括号),一般构造函数,拷贝构造函数,转换构造函数(只有一个标准类型的参数)。

引申:直接调用类名调用构造函数

作用是实实在在产生一个类的对象,但该对象没有名字,一般不能使用,除非用于下列三种情况,1是作为函数返回值,返回一个类的对象,2是用于赋值。3是用于转换构造函数。

为什么需要析构函数:在删除一个对象之前做一些清理工作,另外可以传递信息,让程序员了解最后一次使用该对象后的一些状况。

声明析构函数的方法是: ~类名(参数列表);

定义析构函数的方法是:~类名::类名(参数列表){ 初始化实现 }

二: 静态,常,友元

静态数据成员:一般的类中的数据成员是放在一起的,同一个类的不同对象都有自己独立的这些数据。而成员函数是公用的,同一个类只有一套。调用时都会转到成员函数的入口,并通过传递this指针来进行区分。然而,有的时候需要同一种类的不同对象之间能够有些联系,可以用于对象间的通信,那么模仿函数内部的静态局部变量,可以很容易实现这一点。只要在定义类时,在数据成员的前面加关键字 static ,则把该数据定义成了类的静态数据成员,它被存储在数据段,并且所有同类但不同对象都共用这一个静态数据。倘若这是用sizeof来测试类的大小,那么它是不会包括静态数据成员的。

另外始终要明白一点静态数据成员是属于类的,而不是属于某一个对象的。它的初始化必须在程序的全局区,初始化的形式为: 类名::静态变量名 = 值 ;

静态数据成员的访问,既可以用普通成员函数也可以用下面介绍的静态成员函数来进行。但是既然已经有了静态成员函数这一概念,那么就应该提倡以静态成员函数来访问静态数据成员。静态成员函数也是属于类的,调用方法为 类名::静态成员函数名。当然也可以使用 对象名.静态成员函数名 的方法。另外注意很重要的一点,因为静态成员函数时属于类的,在调用该函数时是不会传递this指针的,也就是说,静态成员函数是断不可访问非静态数据成员的。

常对象

为什么需要常对象?声明了一个类,那么通过类可以创建很多对象,这些对象可能会被该变内部数据的值,这很正常。但总有的时候需要一个对象,其里面的数据时不能被改变的。这既是常对象。但是调用常对象的成员函数时,很可能会更改数据成员,所以C++只允许常成员函数来访问常对象的数据成员。否则编译出错。常成员函数的声明和定义都必须在后面加 const 关键字。

如果不得不在常成员函数中修改数据成员,那么在定义该类时可以使用关键mutable.

另外如果在类中的数据成员前加const关键字,就变成了常数据成员,其初始化只能通过初始化表进行。

友元函数

作用:允许本类的成员函数以外的函数访问所有的数据成员。

三 :操作符重载 

    操作符重载的概念:对于重载的概念,从函数重载已经有所领悟,其实就是编译器对于相同名字的东西,它能够根据某些性质的不同而确定的调用不同的实现方式。C++本身或者说是C语言本身,对于操作符已经具有了重载的特性。例如对于整形数据的加法和对浮点型数据的加法都使用的是操作符“+”,然而其具体的实现是不相同的。从广义上讲,C++中的类可以看做是一种新的数据类型,而且C++始终是围绕类和对象来编程的。但是显而易见的是C++编译器不可能对类的操作符操作具有事先约定,因为类的多元化使这种想法不可能实现,那么只能寄希望与C++提供一种机制,可以让用户自己来定义对相同的类或者不同的类之间进行操作符操作,这种机制就是操作符重载机制。但是要清楚一点,操作符重载的重点不在于重载,而在于操作符的实现。

操作符重载的实现方法,主要就是定义一个函数,这个函数具有和普通函数相同的地方,也有其特殊的地方,而最关键的是,把它定义成什么属性的函数。是类似与C语言的最一般的函数,还是将其定义为类的成员函数,抑或是友元函数。应该说,这三种方式都是可以的,因为操作符重载函数本质上就是函数。然而由于它的特殊性,这三种属性的定义方式各有优缺点。如果定义成最一般的函数,那么它是不能直接访问类的私有数据成员的,它必须依靠类的对外接口来进行对类的私有数据的读取,这样显然是低效的,所以这种方法不提倡使用。如果类的成员函数,那么它的定义和具体调用在形式上是不同的。

它的定义是这样的:  返回类型  类名::operate @(形参列表) 其中@ 用来指代具体的那一种操作符。而且如果是类的成员函数,那么形参列表是不包含第一个操作数的!因为它是类的成员函数,在调用时是会隐式传递this参数的,就相当于是把第一个操作数的信息传递给了该函数。在调用该函数时(假设是双目操作符),那么 C1 @ C2就是调用该函数的形式。他就相当于是 C1.operate @(C2)。所以对于这种定义和实际使用的形式不一致性要做到心中有数。

如果是一般函数,并且把它作为类的友元函数,那么的形参列表就很容易理解,必须要两个操作数的形参了。定义语法和成员函数是相同的:

返回类型  类名::operate @(形参列表)。如果是双目运算符,那么它的具体调用形式为:C1 @ C2 ,它就相当与 operate @(C1 , C2)。

了解了双目运算符重载的方法,那么运算符重载就相当于是掌握了一大半。单目操作符的重载对于类的成员函数来说一般是不需要参数的,因为它成员函数在调用时会自动传递this参数,而如果是友元函数,那么它是需要参数的。另外对于像 ++ 和 ++ 这样的单目操作符,它是具有两种形式的,可以放在变量前面的,也可以是放在变量后面的,那么对于这种不同,C++是有约定的。如果是成员函数,参数为空,那么是前置定义,如果形参列表有一个整形,那么是后置的。对于单目操作符个人觉得用成员函数来定义,更加妥当。

除此之外还有一种强制类型转换操函数。可以把它看做强制转换操作符的重载。它不需要返回值。其形式(成员函数)为:    

operator 类型名()

    {实现语句}

有几点需要明白。强制类型转换适用于把一个类对象转换为一个确定的数据类型。并且在使用时不需要显示的说明。例如类型名为 double 。那么 在程序中,如果有这样的语句:

Double  x,y;

Student c; //Student为一个类名

且在Student类中定义了该类的强制转换函数,那么语句:

x = y + c ; 是合法的。当编译器遇到 操作符 “+” 时发现两边的数据类型不相同,且有没有该形式的操作符重载,但是有Student的强制转换函数,就会把c强制转换为double型。

    

四: 继承与派生

    虚基类

五: 虚函数与多态

        赋值兼容规则

你可能感兴趣的:(编程,c,工作,嵌入式,语言,编译器)