C++中实现面向对象的程序设计(一):类和对象

在学习 C 和 C++ 时就了解到, C++ 是在 C 的基础上发展而成的,它保留了基于过程的与语言特征,但又丰富了面向对象的机制。此前学习 C++ 只接触了其基于过程的程序设计,后续在学习 Java 是才正式接触了面向对象的思想,本系列将通过使用 C++ 语言实现面向对象的程序设计。

一、类的声明和对象的定义

类的声明:一般形式如下

class 类名{
    private:
        私有的数据和成员函数;
    public:
        公用的数据和成员函数;
};

成员访问限定符:private, public, protect

(1)如果在类的定义中既不指定 private ,也不指定 public ,则系统就默认为是私有的。

(2)被声明为 private 成员只能被本类中的成员函数引用,类外不能调用(友元类除外)。

(3)被声明为 public 成员既可以被本类中的成员函数所引用,也可以被类的作用域内的其他函数引用,外界可以调用。

(4)用 protect 声明的成员称为受保护的成员,它不能被类外访问,但可以被派生类的成员函数访问。

(5)现在 C++ 程序多数先写 public 部分,把 private 部分放在类体的后部,但不论先出现 private 还是 public ,类的作用是完全相同的。

对象的定义:一般采取先声明类类型,再定义对象。

类名 对象名;

二、类和对象的特征

(一)类的成员函数

与一般函数的区别:它是属于一个类的成员,出现在类体中,可以被指定为 private, public 或 protecte。若声明为 private 则它的作用是支持其他函数的操作,是类中其他成员的工具函数。

在类外定义成员函数:可以在类体中只对成员函数进行声明,而在类的外面进行函数定义,但必须在函数名前面加上类名,并使用“ :: ”作用域限定符。

class Student{
    public:
        void display();
    private:
        int num;
        string name;
        char sex;
};
void Student::display(){
	cout<<"num:"<<num<<endl;
	cout<<"name:"<<name<<endl;
	cout<<"sex:"<<sex<<endl;
}

内置成员函数:如果在类体中定义的成员函数中不包括循环等控制结构,C++ 系统自动地对它们作为内置( inline )函数来处理,可以大大减少调用成员函数的时间开销。

对在类体内定义的函数一般都省写 inline ,但如果成员函数在类体外定义,系统并不把它默认为内置函数,如果想指定为内置函数应当用 inline 作显式声明。

如果在类体外定义 inline 函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或者写在同一个源文件中),否则编译时无法进行置换。

只有在类外定义的成员函数规模很小而调用频率较高时,才指定为内置函数。

成员函数的存储方式:同一类的不同对象中的数据成员的值一般是不相同的,而不同对象的函数代码是相同的,在存储时一个对象所占用的空间只取决于该对象中数据成员所占的空间,而用一段空间来存放共同函数的目标代码。

(二)类的封装性和信息隐蔽

公用接口与私有实现的分离:公用成员函数是用户使用类的公用接口,或者说是类的对外接口;类中被操作的数据是私有的,类的功能的实现的细节对用户是隐蔽的,这种实现称为私有实现。这种就形成了信息隐蔽。

类声明和成员函数定义的分离:在面向对象的程序开发中,往往把类的声明(其中包含成员函数的声明)放在指定的头文件中,用户如果想用该类,只要把有关的头文件包括进来即可。

(1)类声明头文件是用户使用类库的公用接口,类声明和函数定义是分别放在两个文件中的。

(2)实际上,一个 C++ 程序是由 3 个部分组成的:类声明头文件(后缀为 .h )、包括类成员函数定义的类实现文件(后缀为 .cpp )、类的使用文件(后缀为 .cpp )即主文件。

(3)在系统提供的头文件中只包括对成员函数的声明,而不包括成员函数的定义,对成员函数的定义是单独放在另一个文件中,单独编译。

(4)实际工作中会见若干个常用的功能相近的类声明集中在一起,形成各种类库。类库包括两个组成部分:包括类声明的头文件、已经过编译的成员函数的定义(目标文件)。

三、类和对象的使用

(一)构造函数

构造函数是处理对象初始化的一种特殊成员函数。建立类对象时会自动调用构造函数,不需要用户调用,也不能被用户调用。

(1)无参数的构造方法:构造函数名(){ }

(2)有参数的构造方法:构造函数名(类型1 形参1, 类型2 形参2, …){ }

(3)参数初始化表:构造函数名( 参数表 ):成员初始化表{ }

Student(int n,char s,nam[]):num(n),sex(s){
    strcpy(name,nam);//数据元素是数组不能在参数初始化表中初始化
}

(4)使用默认参数的构造函数:定义对象时未指定初始值则使用默认值。

class Box{
    public:
        Box(int h=10,int w=10,int len=10);
        int volume;
    private:
        int height;
        int width;
        int length;
};

Box::Box(int h,int w, int len){
    height =h;
    width=w;
    length=len;
}

(二)析构函数

当对象的生命期结束时,会自动执行析构函数。它的函数名是类名的前面加一个“ ~ ”符号。

(1)析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。

(2)析构函数没有函数类型和函数参数,不能被重载。一个类可以有多个构造函数,但是只能有一个析构函数。

(3)如果用户没有定义析构函数,C++ 编译系统会自动生成一个析构函数,但他只是徒有析构函数的名称和形式,实际上什么操作都不做。

(4)对同一类存储类别的对象而言,先构造的后析构,后构造的先析构。

(三)对象数组

在建立数组时同样需要构造函数:

(1)如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供实参。

Student stud[3]={60,70,78};    //合法,3个实参分别传递给3个数组元素的构造函数

(2)如果构造函数有多个参数,在定义数组时需要在花括号中分别写出构造函数名并在括号内指定实参。

Student stud[3]={
    Student(1001,18,87),
    Student(1002,19,76),
    Student(1003,18,72)        //分别调用3个元素的构造函数,分别提供3个实参
};

(四)this 指针

this 指针是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址。

this 指针是隐式使用的,它是作为参数被传递给成员函数的,这些操作在编译系统中会自动实现,在需要的时候也可以显式地使用 this 指针。

(五)公用数据的保护

常对象:凡希望保证数据成员不被改变的对象,可以声明为常对象。

(1)定义常对象的一般形式为:类名 const 对象名(实参表) 或 const 类名 对象名(实参表) 。

(2)常对象只能调用它的常成员函数,常成员函数可以访问常对象中的数据成员,但不允许修改常对象中数据成员的值。

(3)如果一定要修改常对象中某个数据成员的值,可以把该数据成员声明为 mutable ,把const声明为可变的数据成员。

(4)指向对象的常指针定义的一般形式为 类名 *const 指针变量名 ,指向常对象的指针变量定义的一般形式为 const 类型名* 指针变量名

(5)如果一个变量已被声明为常变量,只能用指向常变量的指针指向它。

常对象成员:可以把对象的成员声明为const,包括常数据成员和常成员函数。

(1)只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常数据成员赋值。

(2)如果将成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改他们。声明常成员函数的一般形式为 类型名 函数名(参数表) const

(3)常对象只能保证其数据成员是常数据成员,只能调用 const 成员函数,而不能调用非 const 成员函数。

(4)常成员函数不能调用另一个非 const 成员函数。

(六)对象的动态建立和释放

可以使用 new 运算符动态地分配内存建立对象,用 delete 运算符释放这些内存空间销毁对象。用 new 运算符动态分配内存后将返回一个指向新对象的指针,需要定义一个指向本类对象的指针变量存放该地址。

Box *pt;                    //定义一个指向Box类对象的指针变量pt
pt=new Box;                 //在pt中存放新建对象的起始地址

cout<<pt->height;           //输出该对象的height成员
cout<<pt->volume();         //调用该对象的volume函数,计算并输出体积

Box *pt=new Box(12,15,18);  //在执行new时对新建对象初始化

delete pt;                  //释放pt指向的内存空间

(七)对象的赋值和复制

对象的赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。而对象的复制则是从无到有地建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值)。

对象的赋值:一般形式为 对象名 1 = 对象名 2 

对象的复制:一般形式为 类名 对象2 ( 对象1 )类名 对象名 1 = 对象名 2 

(八)静态成员

静态数据成员:如果希望各对象中的数据成员的值是一样的,就可以把它定义为静态数据成员,以关键字 static 开头。

(1)静态数据成员是在所有对象之外单独开辟空间,只要在类中指定了静态数据成员,即使不定义对象,也为静态数据成员分配空间。

(2)静态数据成员可以初始化,但只能在类体外进行初始化,其一般形式为 数据类型 类名::静态数据成员名=初值; ,只在类体中声明静态数据成员时加 static ,不必在初始化语句中加 static 。

(3)静态数据成员既可以通过对象名引用,也可以通过类名来引用。

静态成员函数:在类中声明函数的前面加 static 就成了静态成员函数,它是类的一部分而不是对象的一部分。

(1)如果要在类外调用公用的静态成员函数,要用类名和域运算符,实际上也允许通过对象名调用静态成员函数。

(2)静态成员函数没有 this 指针。

(3)静态成员函数主要用来访问静态数据成员,而不访问非静态成员,但并不是绝对不能访问本类中的非静态成员,只是不能进行默认访问。

(九)友元

在 C++ 中,友元用 friend 声明,可以访问与其有好友关系的类中的私有成员。

友元函数:在本类以外的其他地方定义了一个函数(可以是不属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用 friend 对其进行声明,此函数就称为本类的友元函数。

(1)将普通函数声明为友元函数

class Time{
    public:
        friend void display(Time &);
    private:
        int hour;
        int minute;
        int sec;
};
void display(Time &t){
    cout<<t.hour<<":"<<t.minute<<":"<<t.sec<<endl;
}

(2)友元成员函数

class Date;    //对Date类提前引用声明
class Time{
    public:
        void display(Date &);
    private:
        int hour;
        int minute;
        int sec;
};
class Date{
    public:
        friend void Time::display(Date &);
    private:
        int month;
        int day;
        int year;
};
void Time::display(Date &d){
    cout<<d.month<<"/"<<d.day<<"/"<<d.year<<endl;
    cout<<hour<<":"<<minute<<":"<<sec<<endl;
}

友元类:可以将一个类(例如 B 类)声明为另一个类(例如 A 类)的“朋友”。这是 B 类就是 A 类的友元类,友元类 B 中的所有函数都是 A 类的友元函数,可以访问 A 类中的所有成员。

(1)声明友元类的一般形式为:friend 类名;

(2)友元的关系是单向的,不能传递的。

(3)除非确有必要,一般并不把整个类声明为友元类,而只将确实有需要的成员函数声明为友元函数。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

STRANGEX-03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值