C++类的总结(轻松语言版)

来源:互联网 发布:太极拳教学软件 编辑:程序博客网 时间:2024/05/22 20:12

1. 常成员函数

由于数据封装在类的内部,在处理一些问题的时候就需要小心翼翼,不能把成员数据破坏了。以前我们介绍使用const来保护变量(就变成了常量),或保护指针所指向的内容,那么在类中,我们也可以使用const这个保留字来保护成员数据不被成员函数改变。我们把这种成员函数称为常成员函数。它的写法就是在函数的参数表后面加上一个const,比如:

   int readi() const;//通过该函数读取idata,但不能改变任何成员数据

   char readc() const;//通过该函数读取cdata,但不能改变任何成员数据

使用常成员函数,就保证了成员数据的安全,在此函数中任何修改成员数据的语句将被编译器拒之门外。

2. 构造函数应该是一个公有的成员函数,并且构造函数没有返回值类型;定义成私有或保护是允许的。构造函数至少要有一个是公有的,不然就不能用来生成任何对象;而析构函数因为只能有一个,所以必须是公有的。

3. 拷贝构造函数(复制构造函数):

三个结论:

(1)拷贝构造函数可以读出相同类对象的私有成员数据;

(2)拷贝构造函数的实质是把参数的成员数据一一复制到新的对象中;

(3)拷贝构造函数也是构造函数的一种重载

默认拷贝构造函数

我们已经知道构造函数有默认构造函数,其实拷贝构造函数也有默认的拷贝构造函数。所谓默认拷贝构造函数是指,用户没有自己定义拷贝构造函数时,系统自动给出的一个拷贝构造函数。默认拷贝构造函数的功能是将对象的成员数据一一赋值给新创建的对象的成员数据,如果某些成员数据本身就是对象,则自动调用它们的拷贝构造函数或默认拷贝构造函数。

4. 静态数据成员属于某一个类而不属于某一个具体的对象的。其声明与定义,举例如下:

xxx.h文件

class base

{

private:

    static const int _i;//声明,标准c++支持有序类型在类体中初始化,但vc6不支持

};

xxx.cpp文件

    const int base::_i=10; // 定义(初始化)时不受private和protected访问限制.

注:不要试图在头文件中定义(初始化)静态数据成员。在大多数的情况下,这样做会引起重复定义这样的错误。即使加上#ifndef #define #endif或者#pragma once也不行。

5. 静态成员数据是某一个类所具有的属性,而不是某一个对象的属性,所以它的存在并不依赖于对象。那么,如果一个类没有任何对象实例时,所有的普通成员函数都无法使用,我们该如何访问私有的静态成员数据呢?

既然成员数据可以属于某一个类而不属于某一个具体的对象,成员函数能否这样呢?答案是肯定的。在C++中,除了有静态成员数据,还有静态成员函数。静态成员函数也是属于某一个类而不属于某一个具体的对象的。静态成员函数的声明方法为:

    static  返回值类型  类名::函数名(参数表);

不过,在定义静态成员函数时,却不能出现static。

class Node//声明一个链表结点类

{

public:

       staticint allocation();    //声明静态成员函数定义

private:

       staticint count;       //静态成员数据,存储分配结点个数

};

 

int Node::allocation()      //在定义静态成员函数时不能出现static

{

       returncount;         //返回已分配结点数

}

int main()

{

       cout<<"Node Allocation:" <<Node::allocation() <<endl;  //无对象时,调用静态成员函数

       Nodeb;

       cout<<"Node Allocation:" <<b.allocation() <<endl;         //通过对象,调用静态成员函数

       return0;

}

6. 将链表结点类的实例对象作为链表类的成员数据。这称为对象的组合,它与类的继承也是完全不同的概念。继承(Inheritance)是概念的延续,子类和父类一般都是概念扩展的关系,我们通常把这种关系称为“是”关系。比如:本科生是学生,自行车是交通工具。而对象的组合是因功能需求产生的从属关系,我们通常把这种关系称为“有”关系。比如:链表有一个头结点,电脑有一个中央处理器等等。

但继承不是聚合。

聚合和组合的区别在于:

聚合关系是“has-a”关系,组合关系是“contains-a”关系;聚合关系表示整体与部分的关系比较弱;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。

而组合比较强,组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。

7. protected保留字,在没有使用继承的时候,它与private的效果是一样的,即无法被直接访问。如果使用了继承,我们就能体会到protected和private的差别。

private(私有)和protected(保护)都能实现类的封装性。private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。public、private和protected对成员数据或成员函数的保护程度可以用下表来描述(公有继承时):

8. 继承的方式:

public是公有继承,或称为类型继承。它主要体现的是概念的延伸和扩展,父类所有的公有、保护成员都将按部就班地继承到子类中。父类的公有成员在子类中依然是公有的,父类的保护成员在子类中依然是保护的。比如程序17.3.1中的学生类和本科生类就是这样的关系。

private是私有继承,或称为私有的实现继承。它主要体现的是父类成员的重用。父类所有的公有、保护成员继承到子类时,类型会发生改变,变成了私有成员。这时,我们可以利用从父类继承而来的成员函数来实现子类的成员函数,并且不必担心外部直接访问父类的成员函数,破坏了子类的秩序。比如我们认为栈是一种特殊的链表,它只能从链表尾部添加或删除结点,栈的压栈和退栈功能可以方便地由链表类的成员函数实现。但是,如果外部还能直接访问从链表类继承而来的成员函数,那么就可以在栈的任何位置插入结点,栈就会被破坏。

protected是保护继承,或称为保护的实现继承。与私有继承类似,它也是体现父类成员的重用。只不过父类的公有成员和保护成员在子类中都变成了保护成员。因此,如果有一个孙类继承了子类,那么父类中的成员也将被继承,成为孙类的保护成员。

public、private和protected三种继承方式可以用下表描述。其中右下角的九个单元格表示各种父类成员在对应的继承方式下,成为子类成员后的性质。

9. 虚函数:

设置虚函数的方法为:

在成员函数的声明最前面加上保留字virtual;

但不能把virtual加到成员函数的定义之前,否则会导致编译错误。

虚函数作用:

用父类指针指向不同的子类对象,调用同名成员函数时,分别调用不同子类相应的成员函数。

与重载函数的冲突:

    多态是在程序员没有指定调用父类还是某个子类的成员函数时,电脑根据程序员的要求,揣测并选择最合适的成员函数去执行。但是当成员函数的参数格式不同时(重载),程序员在调用成员函数的各种参数无疑就是在暗示到底调用哪个成员函数。这时电脑岂敢自作主张揣测人类的心思?因此,要使用虚函数实现多态性,至少要使各个函数的参数格式也完全相同。

10.虚析构函数:

虚析构函数不再是运行父类或子类的某一个析构函数,而是先运行合适的子类析构函数,再运行父类析构函数。即两个类的析构函数都被执行了,如果两块资源分别是由父类构造函数和子类构造函数申请的,那么使用了虚析构函数之后,两块资源都能被及时释放。

11. 抽象类与纯虚函数:

在C++中,我们可以把只能用于被继承而不能直接创建对象的类设置为抽象类(Abstract Class)。

之所以要存在抽象类,最主要是因为它具有不确定因素。我们把那些类中的确存在,但是在父类中无法确定具体实现的成员函数称为纯虚函数。纯虚函数是一种特殊的虚函数,它只有声明,没有具体的定义。抽象类中至少存在一个纯虚函数;存在纯虚函数的类一定是抽象类。存在纯虚函数是成为抽象类的充要条件。

那么我们该如何定义一个纯虚函数呢?纯虚函数的声明有着特殊的语法格式:

virtual 返回值类型  成员函数名 (参数表)=0;

请注意,纯虚函数应该只有声明,没有具体的定义,即使给出了纯虚函数的定义也会被编译器忽略。

原创粉丝点击