对象和类
一、面向对象的特征:
1、
封装:封装意味着把对象的属性和方法结合成一个独立的系统单位,尽可能的隐藏。隐藏就会联想到三个关
键字:
private
、
public
、
protected
2、
抽象:抽象的过程是对具体问题进行概括的过程,是对一类公共问题进行统一描述的过程。
3、
继承:子类对象拥有与其基类相同的全部属性和方法,称为继承。子类继承基类,会继承基类的所有属性和
方法。
4、
多态:是指在基类中定义的属性和行为被子类继承后,可以具有不同的数据类型或者表现行为等特征。
例如动物是一个基类,它的子类有老虎、兔子、乌龟等
那么作为动物有一个行为定义为
Move()
,那么这些子类继承下来就会根据自己特性采取不同修改的
Move()
方
法。
在共性中寻找个性
二、重写(覆盖)和重载
1、重写(覆盖)override
override是重写(覆盖)了一个方法,以实现不同的功能。一般用于子类在继承父类时,重写(覆盖)父类中的方法。函数特征相同,但是具体实现不同。
注意:
-
被重写的函数不能是static的,必须是virtual的
-
重写函数必须有相同的类型,名称和参数列表
-
重写函数的访问修饰符可以不同。尽管virtual是private的,派生类中重写改写为public、protect也是可以的
2、重载overload
verload是重载,一般是在一个类实现若干重载的方法,这些方法的名称相同而参数形式不同。但是不能靠返回类型来判断。
注意:
-
位于同一个类中
-
函数的名字必须相同
-
形参列表不同
-
若一个重载版本的函数面前有virtual修饰,则表示他是虚函数,但他也是属于重载的一个版本
-
不同的构造函数(无参构造、有参构造、拷贝构造)是重载的应用
3、重定义redefining
类对基类的成员函数重新定义,即派生类定义了某个函数,该函数的名字与基类中函数名字一样。
重定义也叫做隐藏,子类重定义父类中有相同名称的非虚函数(参数可以不同)。如果一个类,存在和父类相同的函数,那么这个类将会覆盖其父类的方法,除非你在调用的时候,强制转换为父类类型,否则试图对子类和父类做类似重载的调用时不能成功的。
注意:
-
不在同一个作用域(分别位于基类、派生类)
-
函数的名字必须相同
-
对函数的返回值、形参列表无要求
-
若派生类定义该函数与基类的成员函数完全一样(返回值、形参列表均相同),且基类的该函数为virtual,则属于派生类重写基类的虚函数
-
若重新定义了基类中的一个重载函数,则在派生类中,基类中该名字函数(即其他所有重载版本)都会被自动隐藏,包括同名的虚函数
4、多态polymorphism
多态的概念比较复杂,一种不严谨的说法是:继承是子类使用父类的方法,而多态是父类使用子类的方法。
多态分为两类:静态多态性和动态多态性
静态多态性是通过函数的重载实现的
动态多态性是通过虚函数实现的
5、虚函数的作用
可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,而不是基类中定义的成员函数(只要派生类改写了该成员函数)。若不是虚函数,则不管基类指针指向的上哪个派生类对象,调用时都会调用基类中定义的那个函数。
-
虚函数是动态绑定的基础
-
是非静态的成员函数
-
virtual只用来说明类声明中的原型,不能用在函数实现时
-
具有继承性,基类中声明了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数
-
本质:不是重载声明而是覆盖
-
调用方式:通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数
三、函数
1、main函数:由系统自动调用开始执行C++程序的第一个函数
2、外部函数:在定义函数时,如果冠以关键字extern,表示此函数是外部函数
3、内联函数:在函数前加上关键字inline说明了一个内联函数,这使一个函数在程序行里进行代码扩展而不被调用。这样的好处是减少了函数调用的开销,产生较快的执行速度,但是由于重复编码会产生较长代码,所以内联函数通常都非常小。如果一个函数在类说明中定义,则将自动转换成内联函数而无需用inline说明。
4、构造函数:构造函数不能是虚函数。创建派生类对象,将调用派生类的构造函数,而不是基类的构造函数,然后,派生类的构造函数将使用基类的一个构造函数,这种顺序不同于继承机制。因此,派生类不继承基类的构造函数,所以将类构造函数声明为虚拟的没有什么意义。
5、析构函数:析构函数应当是虚函数,除非类不有用做基类。
例:Employee *pe = new Singer;
...
delete pe;
如果使用默认的静态联编,delete语句将调用~Employee()析构函数,这将释放由Singer对象中的Employee部分指向的内存,但不会释放新的类成员指向的内存。但如果析构函数是虚拟的,则上述代码将先调用~Singer析构函数释放由Singer组件指向的内存,然后,调用~Employee()析构函数来释放由Employee组件指向的内存。