重新认识c++

来源:互联网 发布:js table 添加tr td 编辑:程序博客网 时间:2024/06/14 08:25

c语言如此高效,就连某些操作系统都用c来实现,为什们会诞生C++,我想,如果c++没有比c出色的地方,那么c++的出现就没有任何意义了,自从c++诞生起,一直红红火火,所以,在现在众多语言繁杂的世界里,我们要坚信c++绝对有其值得信赖的地方。

c++是在c的基础上发展而来的,而c是面向过程的,所以,c++是并不是纯面向的对象的语言,是基于对象的,并不要因此而忽略c++的超强性能,而正因为是基于对象,我想这正是c++优越于其他语言的地方,虽然没有完全抽象,但是运用起来更加灵活。

 

关于c++,我们所了解的是他的抽象(类实现),多态(重载,虚函数),代码重用(继承,组合)等特性,当然,这也正是c++最基本的特性,但是我们并不能从外部观察c++,而是要有追求的去了解其内部实现。

1,抽象角度看c++

我们知道,c++提供class 关键字允许程序员创建自己的抽象类型,从而产生自己的类型对象,当然,我们所了解的c也提供了struct关键字来创建自己的类型,而c++继承了c中的一切,那么为什么c++还要提供者貌似多余的class?

typedef struct Tag_MySt

{

  size_t a;

size_t b;

};

这是结构体的简单形式,我们知道class有访问属性控制,分别为public,protected,private,但是不要忽略结构体,他也有访问属性控制,不过class默认访问属性石private,而struct默认是public,貌似这样的结果导致class和struct也没什么不同,可是class比struct更优越的地方在于1,可以派生子类,2,更加抽象,(拥有构造函数和析构函数)

class CMycls

{

public:

     CMycls()

      {

      }

    virtual  ~CMycls();

      void ShowData();

private:

    LONG m_data;

};

上面是c++一个简单类的形式,我们知道,c中有内联函数(以关键字inline表示),当我们的程序重复多次用到某段相同的代码时,(这段代码循环(够简单)等),内联函数可以帮助程序改善性能,因为当编译器执行到这段代码时会将这个函数展开,不存在保存函数入口点的压栈和返回时的出栈操作。而class内部所有函数,在设计时默认为内联的(当我们在声明时就实现它),所以class是高效的,不过要满足内联函数的一些基本的要求(声明时就定义,函数本部够简单),请注意,这里我创建了构造函数和析构函数,而且析构函数是虚的,(构造函数不能为虚),因为存在一种情况,就是在向上类型转换时(c++中的自动类型转换,非常安全),基类的指针指向派生类对象,而我们在后面的程序中要销毁这个对象的时候也是利用这个基类的指针删除派生类对象时,能够保证调用的是派生类的析构函数,如果不将析构函数声明为虚的,那么就隐含着一种内存泄露的危险。关于虚函数,我们应该足够了解,虚函数是多态的重要体现,我想任何面向对象的语言,应该都存在这样一种抽象层次,当我们写MFC程序时,发现微软封装的许多类中的函数都声明为虚的(virtual),这就足够说明虚函数的应用是多么的广,如果我们将一个函数声明为虚的,那么将告诉编译器:“我们的这个函数在运行时实行晚绑定”,这个动作是由编译器执行的,我们知道,C中不存在什么早晚绑定的概念,因为C只存在一种绑定形式,那就是早绑定。我们利用虚函数,就能在派生子类的时候,利用父类中的函数名,对该函数进行重新定义而在访问时不会出现紊乱,这就是晚绑定的好处,它告诉编译器当我要选择某个对象时再执行选择。

 

2,多态角度看c++

 c++多态的实现利用了虚函数和重载,分别为动态多态个静态多态,虚函数在上面已经讨论,不过,c++还有更高层次的多态--纯虚函数,实现方法是在虚函数的基础上在赋函数为“0”:例:virtual void func(void)=0;拥有纯虚函数的类称为抽象类,因为这个类不能产生对象(实例化),纯虚函数不能定义,只有在派生子类的时候对子类中的相应的函数进行定义,在这种情况下,我们可以利用一个相同的接口,访问不同对象的方法,就是利用向上类型转换(将子类的对象的地址赋给基类对象的指针或者将子类对象赋给基类对象的引用(必须这样做,否者会产生对象切片)),这样我们可以利用基类对象这一统一的接口访问所有子类的方法,因为子类在某种意义上说是基类的一种类型,基类可以自由访问子类。

 

关于重载,我们知道有简单的函数重载,运算符重载,我们在对函数重载时:例如:

void func(int);

void func(float);

函数重载,必须满足参数类型不同或者参数个数不同。当我们在程序中访问这些同名的函数时,编译器为根据参数自动决定到底调用哪个函数。

对于运算符重载,这里不予讨论,随处可见。

 还有一个重点是覆盖

覆盖指的是在派生类的虚函数覆盖了基类中同名且参数相同的函数。

上面说的虚函数的例子就是覆盖

 

 

3,c++代码重用

c++代码重用,真的值的好好剖析,任何大型的软件项目,不管是出于哪方面的考虑,必须要降低代价,C中我们好像没有看见代码重用的地方,大不了将原来用过的代码保存起来,下次遇到类似的项目时将那段代码复制过来而已,而面向对象程序设计的一个重要特点,就是它提供了一种优越的代码重用的机制--继承,我们所知道的JAVA,C++,C#等,都拥有这个特性,(java不支持多继承),c++继承机制的实现,就是在类的基础上,将父类的一些属性和方法继承下来(MFC中好多类都是依赖于继承),虽然继承有三种属性(public,protected,private),但是我们一般利用的是public继承,只要我们将自己的类设计的足够好就行了。关于这三种继承的不同点,这里不谈。虽然C++支持多继承,但是我们很少用,最起码我很少用,因为我知道多继承可能在后期出现一些小问题。

 

当然在继承时如果基类没有默认的构造函数,我们必须在子类的构造函数中对基类进行初始化,因为继承的初始化层次是先初始化基类,然后依次是各个子类(析构函数执行次序与此相反),这可以利用初始化的列表:例如

class CBase

{

LONG m_T;

public:

        CBase(LONG t);

};

class CChild:public CBase

{

long m_T;

public:

     CChild(LONG t):CBase(t)

   {

   }

};