C++类与对象

  面向对象程序设计在结构化程序设计的基础上,引入了抽象、封装、继承和多态的思想。

  面向对象程序设计将客观世界中的事物称为一个个具体客观对象。将具有相同数据模型的客观对象归纳成一类,这就是面向对象程序设计中的分类,也叫抽象。抽象得到的数据模型称为,其中包含数据成员(属性)函数成员(方法)

一、类与对象

1、类定义

    class 类名  //类声明部分

    {

     public:

        公有成员

     protected:

        保护成员

     private:

        私有成员

    }

    各函数成员的完整定义  //类实现部分

  类定义的语法说明:

  1)class为定义类关键字,类名须符合命名规则

  2)类成员有两种,分别是数据成员和函数成员,某些特殊类可能只含一种成员。

  3)访问控制权限有三种,类通过访问控制权限实现类封装。定义类时将必须被外部访问的成员开放出来,以保证类可正常使用,同时也要隐藏不必要被他人知道成员,防止被误访问。

    C++在定义类时默认将函数成员和数据成员定义为private私有权限,在定义结构体时默认为public公有权限。一般至少保留一个公有成员提供给他人使用。

  4)类定义和声明。类声明部分在大括号中声明数据成员、函数成员,并指定各成员的访问权限。类声明数据成员时不能初始化,声明函数成员只是声明其原型,完整的函数定义代码放在大括号外边的类实现部分。类实现定义函数成员时需要在函数名前加入“类名::”限定,指明该函数属于那个类。

  5)函数成员可以访问本类中的任意位置的数据成员,或调用本类中任意位置的函数成员。不存在先定义声明在访问。类成员具有类作用域,成员间不能同名,除函数成员的重载。

2、数据成员语法细则

  1)数据成员称为属性,是类中的变量,用于保存数据。

  2)数据成员类型可以是基本数据类型和自定义数据类型。

  3)数据成员不能与其他成员同名。

  4)声明数据成员的语法形式类似定义变量,不同的是声明时不能初始化。

3、函数成员语法细则

  1)函数成员又称方法,是类中的函数,其功能主要是对类中的数据成员进行处理。

  2)函数成员可以访问本类中的任意位置的数据成员,或调用本类中任意位置的函数成员。

  3)在类中声明函数成员可以指定形参的默认值,即带默认形参值的函数。

  4)不同函数成员之间可以重名,即重载函数。函数成员和数据成员不能重名。

  5)可以将函数成员定义成内联函数。在类实现是加入关键值inline即可,或者直接在类声明时定义函数成员。

复制代码
//类定义
class Clock
{
//类声明
  private:
       int hour,minute,second;
  public:
       void set();
       void set(int h,int m,int s=0);//函数重载,带默认形参值的函数
       void Show()    //默认定义为内联函数
        {
            cout<<hour<<":"<<":"<<second;
        }
};
//类实现
void Clock::Set()
{
     cin>>hour>>minute>>second;//函数成员访问数据成员不需要加前缀类名
}
void Clock::Set(int h,int m,int s)
{
     hour = h; minute=m; second =s;
}
复制代码

二、对象定义与访问

  使用使用类定义的变量称为该类的一个对象或实例。对象中的公有成员可以访问,非公有成员不能访问,这就是对象中成员的访问控制权限。访问对象中的公有成员需使用成员运算符“.”,以“对象名.成员名”的形式访问对象成员。

  示例:

    Clock obj1;

    obj1.Set();

    obj1.Show();

  对象指针保存某个对象的地址。

  示例:

    Clock obj1;

    Clock *p=&obj1;

    obj1.Set();

    (*p).Set();

    p->Set(); //C++引入了更直观的指向运算符(->),通过指向运算符可以访问对象的数据成员和函数成员。

    obj1.Show();

  注意:C++编译器会在函数成员的形参列表加入 一个该类类型指针(类名 *const this),形参this是隐含的,当函数成员访问数据成员时实际上是通过this->数据成员名进行的数据访问。

三、对象的构造和析构

  和变量一样,对象也有全局对象、静态对象和局部对象之分,也可以动态分配。程序执行时,对象也会经历从分配内存到释放内存的过程,即对象具有生存期。对象的内存分配方式、生存期与变量完全一样。创建对象为对象分配内存空间的过程称为对象的构造,销毁对象释放对象内存空间的过程称为对象的析构。面向对象的程序设计需要定义专门的函数来实现构造与析构的功能,这就是类的构造函数和析构函数

1、构造函数

  执行定义对象语句时,计算机将自动调用对象所属类的构造函数,实现对象的初始化。构造函数是类中的一种特殊函数成员。

  构造函数的几点语法细则:

    1)构造函数与类名相同

    2)构造函数由计算机自动调用,程序员不能直接调用。

    3)构造函数通过形参传递初始值(可指定默认形参值),实现对新创建对象数据成员的初始化。

    4)构造函数可以重载,即可以提供多种形式的对象初始化方法。

    5)构造函数可以定义成内联函数。

    6)构造函数没有返回值,定义时不能写函数类型,写void也不行。

    7)构造函数通常是类外调用,其访问权限应设为public或protected,不能设为private。

    8)一个类如果没有定义构造函数,编译器为其添加一个空的构造函数,称为默认构造函数。其语法形式为: 类名(){}

  构造函数的主要用途有初始化对象的数据成员、显示对象构造过程,或者是在构造对象时申请额外内存等。

2、初始化对象的数据成员

  初始化对象的方法是在类中添加构造函数,然后在定义对象时给出初始值。语法形式为: 类名::类名(形参列表){}   //值得注意第一个类名表示那个类的构造函数,第二个类名为构造函数名。

  示例:

复制代码
Clock::Clock()  //不带形参的构造函数
{
    hour=0;minute=0;second=0;
}
Clock::Clock(int x,int y,int z) //带形成的构造函数
{
    hour=x;minute=y;second=z;
}

//可以将上述两个从重载函数改写成一个带默认形参值的构造函数
Clock::Clock(int x=0,int y=0,int z=0) //带默认形参值的构造函数
{
    hour=x;minute=y;second=z;
}
//注意第二、三种构造函数,需要在类中先声明在类实现
复制代码

  总结一下:每定义一个对象就会调用一次构造函数,但在定义对象指针或对象引用并不会并不会创建对象也就不会调用构造函数。

3、用已知对象初始化当前新建对象(即拷贝构造函数)

  拷贝构造函数接收一个已存在的本类对象引用,然后将该对象的数据成员对应地赋值给当前对象的数据成员,实现用一个已知对象来初始化新建对象的功能。如果程序员没有为类定义拷贝构造函数,则编译器在编译时也会自动添加一个默认拷贝构造函数,其作用就是将该对象的数据成员对应地赋值给当前对象的数据成员。拷贝构造函数的形参只有一个且必须是本类的引用。

  示例:

复制代码
Clock::Clock(Clock &obj)
{
    hour=obj.hour;minute=obj.minute;second=obj.second;
}
//使用
Clock obj1(10,30,50);
Clock obj2(obj1);
//相当于
int x = 10;
int y = x;
复制代码

4、析构函数

  计算机销毁对象,释放其内存空间,这个过程就是对象的析构。计算机在销毁对象时将自动调用对象所属类的析构函数。与构造函数一样析构函数也是类中的一种特殊函数成员。

  析构函数的几点语法细则:

    1)析构函数名必须为“~类名”。

    2)析构函数由计算机自动调用,程序员不能直接调用。

    3)析构函数没有形参。

    4)析构函数没有返回值,定义时不能写函数类型,void也不行。

    5)析构函数通常是类外调用,其访问权限应设为public或protected,不能设为private。

    6)一个类如果没有定义析构函数,编译器为其添加一个空的析构函数,称为默认析构函数。其语法形式为: ~类名(){}

  如果在类的构造函数中进行了内存的动态申请,在析构函数中需要释放其动态分配的内存。由此可延伸出来深拷贝和浅拷贝的概念。

  若类中存在一个指针成员变量表示一组数据和一个字符串,通过默认拷贝构造函数进行拷贝构造一个新对象时,新旧两个对象的该指针成员会指向同一片内存区域,实现指针成员的值相同。但是带来的问题是如果一个对象通过指针改变该地址空间的值,另一个对象的指针成员的所指也会相应改变,我们将这种复制指针变量的形式称为浅拷贝

  另一种实现方法,拷贝构造一个新对象时,程序员自己定义一个拷贝构造方法,先对指针变量成员分配空间,在将旧对象指针变量所指向的值复制到新变量所指向的地址空间内,这种复制指针变量的形式称为深拷贝

  简答总结一下深浅拷贝的区别,浅拷贝不分配空间,只是两个指针指向同一个地址空间;深拷贝是先分配空间,在复制内容。

  注意:如果构造函数中动态分配了内存,那么就需要编写析构函数,用delete语句释放这些动态分配的内存;同时还需要把编写拷贝构造函数进行深拷贝,即新建对象动态再分配同样多的内存,然后复制内容。

  最后总结一下以上内容:

    1) 定义类。定义类注意五大要素,即数据成员、函数成员、各成员的访问权限、构造函数和析构函数。

    2)定义对象。类当作一种自定义数据类型来定义变量,所定义的变量称为对象,计算机执行定义对象语句就是按照类的五大要素创建类的对象,所创建的对象具有类的数据成员、函数成员及访问权限。

    3)访问对象。访问对象就是通过接口操作内存中的对象,读写对象中的公有数据成员或调用其中的公有函数成员。

posted @   KylinZhuang  阅读(140)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示