你懂得C,所以C++也不在话下

前言:C++最初诞生时,仅仅被称作带类的C。这说明C和C++是一衣带水的关系,随后C++扩充了很多特性,成为了面向对象的一个语言,真正成了扛把子。那么C++有什么优势呢?举个例子类比,一个C代码项目就像是一个冰柜,所有的东西都装在一块,且不说会不会“窜味儿”,看起来很没条理。而C++就像是一个冰箱,有冷藏室冷冻室,冷藏室还有放鸡蛋的地方,放蔬菜的地方...当然这只是其中最早的一个好处:封装性。但是C语言没法写出C++的特性,这就依赖于下面要介绍的C++的其他特性。

一. C++ beyond C

C++扩展了一些新的特性,其中最主要的包括以下几个:

  • 封装(类)
  • 继承
  • 多态
  • STL

接下来会简单介绍一下每一个特性,最后看一下STL的主要的容器。

二. 特性介绍

2.1 封装(类)

通过抽象,类把一类东西的属性和方法封装到了一起。这就是美其名曰“面向对象”的概念。就是代码的组织不再是流程控制,而是对象的组织。C语言的流程控制是通过判断条件来跳转执行的,而C++对象的组织则是通过继承,多态等方式组织的。

class Test  
{  
	public:  
	    int x_;  
	    void init(int x, int y,int z);  
	    void display()  
	    {  
	        cout<< x_ << endl;  
	    };  
	private:  
	    int y_;  
	protected:  
	    int z_;  
};  

上面是一个类的典型定义,从中可以看出把数据和函数封装到了一块,并通过关键字public,private,protected来限制访问权限。

从上面的定义看,跟C中的结构体也可以实现类似的功能,但是C语言没法设置访问权限,也有一些人喜欢把C写成C++风格的。

2.2 继承

我们上面提到过,C语言是组织流程,所以,代码中到处都是条件判断和流程处理。但是在C++中,要组织的却是一个个对象。要先抽象,定义出对象的雏形。然而,还有一个问题必须解决,C++面向的是对象,可世间对象千千万,大千世界最不缺的就是差异,那么千千万不同的种类以及实例化的对象该怎么管理呢?答案就是继承和多态。继承解决相同的部分,多态解决差异的部分。这一节就先介绍继承。

继承使得新的类不必完全重新定义,而是借助于已有的类定义,这大大的减轻了创建管理类的工作。继承可以使得新类从基类中获取属性和方法(public继承时)。

class base{
    public:
        void cacl(int n) {printf("good");}
    private:
        int i,j;

};

class next : public base{
    public:
        void mix(int m) {printf("well");}

};

关于创建新的类时是否需要采用继承的办法,需要注意:如果新类时基类的一种,如,哈士奇是狗的一种,哈士奇还有其他一些属性和方法,如卖萌;这个时候,哈士奇类可以继承狗这个类。另一种情况是,眼睛是头的一部分,但不能说眼睛是基类,头是派生类,因为头显然没有看东西这个功能。这个时候,创建头这个类时,应该在头这个类种包含眼睛这个类,而不是继承。

class head{
	public:
		void cacl(void);
		class eye eyes;
	private:
		int len;

};

2.3 多态

好了,要创建新类,先抽象找共性,通过继承新的类建立起来了,然而,很快就会遇到一个问题:类的行为千差万别,即使对于同一个方法也会有不同的表现,如对于吃饭,印度人是手抓着吃,中国人是用筷子,欧美人是用刀叉。这种情况下,如果定义一个基类,要不要定义吃饭这个方法呢?如果不定义,那么各个派生类类就得定义自己的吃饭方法,更要命的是,一个类和另一个类可能不光吃饭不相同,几乎所有的方法实现起来都不相同...比如,睡觉,休闲,运动都不相同。那么各个派生类都去定义自己的一套,继承不就成了摆设了么?说好的代码重用呢?

这就是多态的用处,多态可以实现对于每个派生的类,当调用同一个方法时,实现不同的行为,即调用到自己的方法实现。C++的多态可以分为两种:

  • 静态多态
  • 动态多态

所谓的静态多态就是通过函数重载的办法实现的,重载可以针对操作符也可以针对函数。用重载时,函数名字相同,参数和返回值不同,实际上是在编译阶段根据参数的类型来确定使用哪个函数。

而动态多态是通过虚函数的方式实现的,也就是在基类中先定义虚函数,然后在派生类中定义自己的方法,然后覆盖基类的方法。

#include<iostream>
using namespace std;

class Base
{
	public:
	    virtual Base* FunTest()
	    {
	        cout << "victory" << endl;
	        return this;
	    }
};

class Derived :public Base
{
	public:
	    virtual Derived* FunTest()
	    {
	        cout << "yeah" << endl;
	        return this;
	    }
};

int main()
{
    Base b;
    Derived d;

    b.FunTest();
    d.FunTest();

    return 0;
}

2.4 STL模版库

为了提高C++的开发效率,对代码能够做到重用,STL诞生了,它一开始并不是C++的一部分,STL实际上提供了泛型编程在C++上的实现。STL考虑的事情是:对于一个排序功能,无论使用哪种数据结构,数组也好,链表也好;无论哪种数据类型,int也好,float也好,都应该能够实现排序功能。为了这个目标,STL在实现时,划分成了三个部分实现

  1. 容器
  2. 算法
  3. 迭代器

容器提供了常用的数据结构,set,map,list,vector等;算法提供了排序等几十种算法;而迭代器呢?迭代器实际上就是要匹配容器和算法,根据不同的容器元素类型,采用对应的排序实现。如,数组排序和链表排序。

那么再回过头来看,STL是标准模版库的简写。模版是什么?我们前面说到过STL是为了提供泛型支持,回想一下会发现,函数重载是不是也解决了部分问题?(函数重载通过实现多个参数不同的原型,也能提供部分泛型支持)。但是,一直重载函数也不是一个有效的办法来解决泛型支持问题,所以,模版诞生了。当然,这里一直没有说类模版,只提到了函数模版。模版的典型定义如下:

template<typename(或class) T>
T fuc(T x, T y)
{
    T x;
    //……
}

接下来简单介绍一下STL提供的几种容器:

2.4.1 几种常用容器

c++中有两种类型的容器:顺序容器和关联容器,顺序容器主要有:vector、list、deque等。其中vector表示一段连续的内存地址,基于数组的实现,list表示非连续的内存,基于链表实现。deque与vector类似,但是对于首元素提供删除和插入的双向支持。关联容器主要有map和set。map是key-value形式的,set是单值。

  • vector - 需要包含#include<vector>

    vector提供的操作主要有:

    • vec1.push_back(100);
    • vec1.size();
    • vec1.empty();
    • vec1.pop_back();
    • vec1.insert(vec1.end(),5,3);
    • vector::const_iterator c_iter = vec1.begin();
  • list - 需要包含#include<list>

    list是一个双向链表,提供的主要操作是:

    • lst1.push_back(10);
    • lst1.pop_back();
    • lst1.sort();
    • lst1.reverse();
    • lst1.remove(2);
  • map - 需要包含头文件#include<map>

    map提供了一种存放<key,value>对儿的结构,并自动排序。主要的操作是:

    • map1.insert(make_pair<int,string>(4,"V5"));
    • map1.erase(3);
    • map1.size();

三. 总结

C++提供了面向对象的设计方法,很多特性都是围绕着类和对象的创建,管理,使用展开的。本文只简单介绍了C++中的一些关键东西,还有更多细节的东西,如构造函数,析构函数,智能指针等暂时略去不表。但是只要掌握了C++的核心内容,细节使用随着经验积累,自然会心中有天地。

posted @ 2018-04-05 18:17  AISEED  阅读(318)  评论(0编辑  收藏  举报