C++——类与对象

文章目录

  • 一、类的定义
  • 二、类成员的访问控制
    • 2.1 Public类型
    • 2.2 Private类型
    • 2.3 Protected类型
  • 三、类的成员函数
    • 3.1 成员函数的实现
    • 3.2 带默认形参数值的成员函数
  • 四、类的对象大小的计算
  • 五、类成员函数this指针
    • 5.1 this指针的引出
    • 5.2 回答几个问题:
  • 六、对象


一、类的定义

首先我们举一个很常见的例子:钟表,时钟类的定义如下:

class Clock
{
public:
    void SetTime(int newH,int newM,int newS);
    void ShowTime();

private:
    int hour,minute,second;
};

这里,封装了时钟的数据和行为,分别称为Clock类的数据成员和函数成员,定义类的语法形式如下:

class 类名称
{
public:
    外部接口;
protected:
    保护型成员;
private:
    私有成员;
};  

其中public, protected,private分别表示对成员的不同访问权限。
Notes:在类中可以声明函数的原型,函数的实现可以在外部。

二、类成员的访问控制

类的成员包括数据成员以及函数成员,分别描述问题的属性以及行为。
对类成员访问权限的控制,是通过设置成员的访问控制属性而实现的,访问属性有一下3种:

公有类型(public)、私有类型(private)和保护类型(protected)。

2.1 Public类型

公有类型成员定义了类的外部接口。公有成员用public关键字声明,在类的作用域外只能访问类的共有成员。对于时钟的例子,外部只能调用SetTime()和ShowTime()这两种公有类型。

2.2 Private类型

在关键字private后面声明的就是类的私有成员。如果私有成员紧接着类名称,则关键字private可以被省略。私有成员只能被本类的成员函数访问,来自类外部的任何访问都是非法的。对于时钟的例子,hour、minute和second都是私有成员。

2.3 Protected类型

保护类型成员的性质和私有成员的性质相似,其差别在于继承过程中对产生的新类影响不同(本篇文章不做探究)

Notes:一般情况下,一个类的数据成员都应该声明为私有成员,这样,内部数据结构就不会对该类以外的其余部分造成影响。

Notes:在书写时通常习惯将公有类型放在前面,这样便于阅读,因为它们是外部访问时所要了解的。

Notes:在类的定义中,修饰访问属性的关键字可以出现多次。但是一个成员只能具有一种访问属性。例如:

class Clock
{
public:
    void SetTime(int newH,int newM,int newS);

private:
    int hour,minute,secondl
public:
    void ShowTime();
};

三、类的成员函数

类的成员函数描述的是类行为,例如时钟的SetTime()和ShowTime()。成员函数是程序算法的实现部分,是对封装的数据进行操作的方法。

3.1 成员函数的实现

函数的原型声明要写在类体中,原型说明了函数的参数表和返回类型。而函数的具体实现是可以写在类定义之外的。与普通函数不同的是,实现成员函数时要指明类的名称,具体形式为:

返回值类型  类名::函数成员名(参数表)
{
    //函数体
}

3.2 带默认形参数值的成员函数

类的成员函数也可以有默认形参值,其调用规则与普通函数相同,类成员函数的默认值,一定要写在类定义中,而不能写在类定义之外的函数实现中,例如:

class Clock
{
public:
    void SetTime(int newH=  0,int newM = 0,int newS = 0);
    ....
};

这样,如果调用函数时没有给出实参,就会按照默认按照默认形参值将时钟设置到了0点。

四、类的对象大小的计算

一个类的大小,实际就是该类中"成员变量"之和,当然也要内存对齐,例如:

#include 
using namespace std;
class A1
{
public:
    void Fun1()
    {}

private:
    int a,b;
};

class A2
{
public:
    void Fun2()
    {}
};

class A3
{};

int main()
{
    std::cout<<"A1 = "<< sizeof(A1)<<endl;
    std::cout<<"A2 = "<< sizeof(A2)<<endl;
    std::cout<<"A3 = "<< sizeof(A3)<<endl;
    return 0;
}

A1 = 8,A2 = 1,A3 = 1;
Notes:空类比较特殊,编译器给了空类一个字节来唯一标识这个类。

五、类成员函数this指针

5.1 this指针的引出

我们先看一段代码:

using namespace std;
class Clock
{
public:
    void SetTime(int newH = 0,int newM = 0,int newS = 0)
    {
        hour = newH;
        minute = newM;
        second = newS;
    }
    void ShowTime()
    {
       
    }

private:
    int hour,minute,second;
};

int main()
{
    Clock myclock_1,myclock_2;
    myclock_1.SetTime(12,12,12);
    myclock_2.SetTime(0,0,0);
    myclock_1.ShowTime();
    myclock_2.ShowTime();
    return 0;
}

那么思考这样一个问题:Clock类中有SetTime()和ShowTime()两个函数,函数体中没有关于不同对象的区分,那么为何当myclock_1调用SetTime()函数时,函数是怎么知道应该设置myclock_1对象,而不是myclock_2对象呢?

C++中通过引入this指针解决上上述问题:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象,在函数体中所有成员变量的操作都是通过this指针去访问,用户不需要去传递,编译器自动完成。

Notes:

class A1
{
public:
    void Fun(int a)
    {
        b = a;
        this -> b = a;
        (*this).b = a;
    }

private:
    int b;
};

上述3种表示方式是等价的。

Notes:this指针只能在类的成员函数中调用,第一个成员函数的默认参数为:*T const register this , 如: class A{public: int func(int p){}}; 其中,func的原型在编译器看来应该是: int func(A const register this, int p);*它表示当前函数的地址。this指针一般放在成员函数的第一个参数列表中。

5.2 回答几个问题:

1.this指针存在哪里?
答:编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。

2.this指针可以为空吗?
答: 可以为空,当调用函数时,如果函数内部不需要使用到this,也就是不需要通过this指向当前对象并对其进行操作时才可以为空。

3.this指针是什么时候创建的?
答:this在成员函数的开始执行前构造的,在成员的执行结束后清除。

4.this指针如何访问类中变量的? 如果不是类,而是结构的话,那么,如何通过结构指针来访问结构中的变量呢?
答:在C++中,类和结构的区别是:类的成员默认是private,而结构是public。 this是类的指针,如果换成结构,那this就是结构的指针了。

六、对象

如果将类看作是一个自定义的类型,那么类的对象就可以看作
是该类型的变量。声明一个对象和声明一个一般变量相同,采用以下的方式:

类名 对象名;

例如:
Clock myclock;

就声明了一个时钟类型的对象myclock。

定义了类及其对象,就可以访问对象的成员,这种访问方式采用的是“ . ”操作符,访问数据的一般形式为:

对象名.数据成员名

调用函数成员的一般形式为:
对象名.函数成员名(参数表)

例如,访问类Clock的对象myclock的函数成员ShowTime()的方式如下:

myclock.ShowTime()

在类的外部只能访问到类的公有成员,在类的成员函数中,可以访问到类的全部成员。

你可能感兴趣的:(C++,c++,类)