用了C++一段时间,感觉对C++慢慢有了一点认识,在这和大家分享一下。
C++是一款面向对象的语言,拥有面向对象语言的三大核心特性:继承,封装,多态。每一个特性的良好理解与使用都会为我们的编程带来莫大的帮助。下面我就这三个特性讲一下我对C++的理解。
继承
学过面向对象语言的人基本都可以理解什么是继承,但我们为什么要使用继承?
很多人说继承可以使代码得到良好的复用,当然这个是继承的一个优点,但代码复用的方法除了继承还有很多,而且有些比继承更好。我认为使用继承最重要的原因是继承可以使整个程序设计更符合人们的逻辑,从而方便的设计出想要表达的意思。比如我们要设计一堆苹果,橘子,梨等水果类,使用面向对象的方法,我们首先会抽象出一个水果的基类,而后继承这个基类,派生出具体的水果类。如果要设计的水果很多,我们还可以在水果基类基础上,继续生成新的基类,比如热带水果类,温带水果类,寒带水果类等,而后再继承这些基类。这样的设计思想就相当于人类的分类思想,简单易懂,而且设计出来的程序层次分明,容易掌握。
既然继承这么好,那该如何使用继承?
继承虽好但不能滥用,否则设计出来的程序会杂乱不堪。根据上面的介绍,可以发现继承主要用来定义一个东西是什么,比如热带水果是水果,菠萝是热带水果等,即继承主要用来设计一个程序的类的框架,将所要设计的东西用继承来设立一个基本结构。如果想为一个类添加一个行为或格外的功能,最好是使用组合的方式。如果想了解组合的方式,可以看一下比较著名的策略模式。
封装
封装是什么?
在C++中,比较狭隘的解释就是将数据与操作数据的方法放在一个类中,而后给每个成员设置相应的权限。从大一点的角度来说,封装就是将完成一个功能所需要的所有东西放在一起,对外部只开放调用它的接口。
为什么要封装?
我认为模块化设计是封装的本质原因。
对软件设计或其他工程设计,特别是比较复杂的工程,一般都是模块化设计。模块化设计的好处就是可以将一个复杂的系统拆分成不同的模块。每一个模块又可以独立的设计,调试,这就让多人一起做一个复杂的工程成为现实。如果想做到模块化设计,封装是不可缺少的一部分。一个好的模块,比如一块inter的CPU芯片,它有强大的功能,虽然我们不知道它内部是如何实现的,但却可以很好的使用它。
多态
什么是多态?
多态简单的说就是“一个函数,多种实现”,或是“一个接口,多种方法”。多态性表现在程序运行时根据传入的对象调用不同的函数。
C++的多态是通过虚函数来实现的,在基类中定义一个函数为虚函数,该函数就可以在运行时,根据传入的对象调用不同的实现方法。而如果该函数不设为虚函数,则在调用的过程中调用的函数就是固定的。比如下面一个例子
//
//定义一个Duck基类,而后继承Duck派生出一个RedHandDuck类。
//其中display()方法,第一次运行设为普通函数,第二次设为虚函数
#include "iostream"
class Duck {
public:
Duck(){}
~Duck(){}
//定义一个虚函数display
virtual void display(){
std::cout<<" I am a Duck !"<<std::endl;
}
};
class RedHandDuck:public Duck{
public:
RedHandDuck(){}
~RedHandDuck(){}
//重写display
void display(){
std::cout<<" I am a RedHandDuck !"<<std::endl;
}
};
int main(){
RedHandDuck* duck1 = new RedHandDuck();
Duck* duck2 = duck1;
duck1->display();
duck2->display();
std::getchar();
}
第一次运行结果(不使用虚函数):
第二次运行结果(使用虚函数):
由结果可以看到,由于虚函数的使用,Duck对象(可以理解为接口),调用的display()方法是根据传入的对象决定的。这就实现了“一个接口,多种方法”。
从网上看到一个关于多态的介绍,非常精辟,分享给大家
多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。