C++:类和对象(第 1 部分)(类的介绍、类的定义、类的实例化

 2024-02-09 02:03:02  阅读 0

文章目录

1. 面向对象和面向对象的初步认识

C语言是面向过程的,关注过程,分析解决问题的步骤,通过函数调用逐步解决问题。

C++基于面向对象,关注对象。 它将一个事物拆分成不同的对象,并依赖于对象之间的交互。

这是计算机体系结构中的八个伟大想法之一:使用抽象来简化设计 - 减少低级细节,为更高级别提供更简单的模型

2. 课程介绍

C语言结构体中只能定义变量。 在C++中,结构体中不仅可以定义变量,还可以定义函数。

升级为C++中的类,不需要重命名。 可以使用后续的类名直接创建对象。

例如:

typedef int STDataType;
struct Stack
{
    void Init(size_t capacity)
    {
        _array = (STDataType*)malloc(sizeof(STDataType) * capacity);
        if (nullptr == _array)
        {
            perror("malloc fail");
            return;
        }
        _capacity = capacity;
        _top = 0;
    }
    void Push(const STDataType& data)
    {
        _array[_top] = data;
        _top++;
    }
    void Destroy()
    {
        if (_array)
        {
            free(_array);
            _array = nullptr;
            _capacity = _top = 0;
        }
    }
    STDataType* _array;
    int _capacity;
    int _top;
};
int main()
{
    Stack s;
    s.Init(10);
    s.Push(1);
    s.Push(2);
    s.Push(3);
    s.Push(4);
    s.Push(5);
    s.Destroy();
    return 0;
} 

类名就是类型。 创建对象时不需要添加它。 你可以只使用堆栈。 可以在类中定义成员函数。 调用函数时,可以直接使用结构体变量 + 。 + 成员函数格式。

显然,C++ 中的类更加精简。

在C++中,我更喜欢使用类而不是定义类。

3. 类访问限定符

C++实现封装的方式:使用类来组合对象的属性和方法,使对象更加完整,并通过访问权限有选择地向外部用户提供接口。

通过权限访问限定符可以在一定程度上保护类的成员。 C++ 访问限定符分为三种类型:

修改后的成员可以在类外部直接访问。 并且修改后的成员不能在类外部直接访问。 (这里 和 类似)访问权限从访问限定符出现的位置开始应用到下一个访问限定符出现为止。 如果后面没有访问限定符,则范围达到}。 端类默认访问权限为; 默认的访问权限为(为了兼容C语言)

注意:访问限定符仅在编译时有用。 当数据映射到内存时,访问限定符没有区别。

一般来说,将类的成员变量的访问权限设置为。

s.Empty()(成员变量设置为私有)和 == 0(成员变量设置为公共)。 两者相比,前者肯定更好。 前者更加标准化,因为它们都处于相同的抽象级别。 使用这种格式,比如s.Init(10) s.Push(1),显然前一种更好。 s.Empty() 顾名思义,你就知道这个函数返回栈对象是否为空的结果。 而==0则需要进一步思考,代码可读性明显降低。

问题:C++中的类和类有什么区别?

回答:

4. 类定义

class ClassName
{
    // 类体: 由成员函数和成员变量组成
};  // 一定要注意后面的分号

class是定义类的关键字,是类的名称,{}是类的主体,{}是域。 注意类定义结束后的分号不能省略。 类体中的内容称为类的成员: class 中的变量称为类的属性或成员变量; 类中的函数称为类的方法或成员函数。 定义类的两种方式,声明和定义,都放在类体中。 注意:如果成员函数位于类定义中,编译器可能会将其视为内联函数。

类声明放在头文件.h文件中,成员函数定义放在.cpp文件中。 注意:在定义成员函数名之前,需要加上类名::(每个类都是一个域,需要用::来表示函数在哪个域中间)

更推荐使用第二种定义方法。 类中定义的成员函数默认启用。 您还可以将短成员函数直接放置在类定义中。

正确用法:将长函数和声明分开,不要将短函数声明和定义分开。

成员变量命名规则建议

如果我们定义一个Date类,需要编写一个初始化年份的成员函数,那么下面代码中的两年指的是什么?

这里的两年是函数创建的局部变量,会给自己赋值,这与初衷相悖了。

为了区分,一般内部成员变量名都会在前面加一个_,比如_year

class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << _year << '-' << _month << '-' << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d;
    d.Init(2020, 1, 1);
    d.Print();
    return 0;
}

程序运行结果如下:

5. 课程范围

类定义了一个新的作用域,类的所有成员都在该类的作用域内。 在类外部定义成员时,需要使用::scope运算符来指示该成员使用哪个类作用域。

typedef int STDataType;
class Stack
{
public:
    void Init(int capacity); 
private:
    STDataType* _array;
    int _capacity;
    int _top;
};
// 这里需要指定 Init 是属于 Stack 这个类域的
void Stack::Init(int capacity)
{
  _array = (STDataType*)malloc(sizeof(STDataType) * capacity);
  if (nullptr == _array)
  {
    perror("malloc fail");
    return;
  }
  _capacity = capacity;
  _top = 0;
}

6. 类的实例化

使用类类型创建对象的过程称为类的实例化。

类描述一个对象,类似于模型。 定义一个类并不会分配实际的内存空间来存储它。

以int为例,和int在某些方面是相同的,都表示接下来创建什么类型的对象。 对我来说直接给int赋值显然是不可能的,对于类也是如此。

变量声明和定义的区别在于是否开辟内存空间。 int告诉编译器,如果我需要定义一个int类型的变量,我需要要求操作系统给我分配一个4字节的空间。 只有当我真正定义了一个(int a;)时,才会真正存在一个int类型的对象。

以此类推,类声明也可以让编译器告诉操作系统,如果我需要创建一个类类型的对象,操作系统就会给我分配这么大的空间,相当于一个通知和提醒。 只有当类在实际创建时找到特定的对象时,内存中才会有特定类类型的对象。

一个类可以实例化多个对象。 实例化的对象占用实际的物理空间并存储类成员变量。

int main()
{
    Date._year = 1000;      // 编译失败, 语法错误
    return 0;
}

Date 类没有特定的空间。 只有 Date 类实例化的对象才有特定的年、月、日。

例如,实例化类中的对象就像使用建筑设计图在现实中建造房屋一样。 一个类就像一张设计图,只是一个蓝图,但并没有实际的建筑。 同时,类只是一个被实例化的设计。 对象实际上可以存储数据并占用物理空间。

需要注意的是,对象中不存在成员函数(类方法)。 它实际上是一个普通函数,但仅限于类的域。 调用成员函数的操作与调用普通函数相同。 C++ 命名规则 成员函数和普通函数之间存在区别。

例如,在一个社区中,每户的图纸都是相同的,但每户内部的具体物品是不同的。 类创建的多个实例化对象对应的成员变量可以不同。

每个社区都有公共停车场、花园等,但你不需要指定它们属于哪一个,你只需要知道它们属于这个社区即可。 类对应的成员函数不需要使用类类型生成的对象存储。 ,只要对象是该类类型,就可以调用该类的成员函数。

7、类对象模型计算类对象的大小以及类的实际存储方式。

为了验证C++中的类对象只存储成员变量,编写了如下代码:

typedef int STDataType;
class Stack
{
private:
    STDataType* _array;
    int _capacity;
    int _top;
public:
    void Init(int capacity);
    void Push(STDataType x);
};
class A
{
    
};
class B
{
private:
    char _a;
public:
    void printB()
    {
        cout << _a << endl;
    }
};
class C
{
private:
    char _a;
};
int main()
{
    Stack st;   //类实例化一个对象
    cout << sizeof(st) << endl;
    cout << sizeof(Stack) << endl;
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    cout << sizeof(C) << endl;
    return 0;
}

程序运行如下:

类的大小实际上就是类中“成员变量”的总和。 当然,一定要注意内存对齐。

注意空类的大小。 空课很特别。 编译器赋予空类一个字节来唯一地表示该类的对象。

从这里可以看出:类的对象存储方法是这样的

成员变量存放在类实例化的对象中,类的成员函数则放在公共代码区的类成员函数表中。

有关结构对齐规则的详细信息,请参见

8.this指针的介绍

首先定义一个日期类Date

class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << _year << '-' << _month << '-' << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1, d2;
    d1.Init(2000, 1, 1);
    d2.Init(2010, 10, 10);
    d1.Print();
    d2.Print();
    return 0;
}

程序正常运行:

但仍然存在一个问题:

Date类中有两个成员函数,Init和Print。 函数体中的对象之间没有区别。 那么当d1调用成员函数Init时,函数怎么知道自己应该设置d1对象而不是d2对象呢?

C++通过引入this指针解决了这个问题

C++编译器为每个“非静态成员函数”添加了一个隐藏的指针函数,让指针指向当前对象(函数运行时调用该函数的对象)。 函数体内对“成员变量”的所有操作,都是通过这个指针来访问的。

只不过所有操作对用户都是透明的,即用户不需要经过,编译器自动完成。

this指针的特点 this指针的类型:类类型 * const,即在成员函数中,this指针不能赋值,只能在成员函数内部使用。 这个指针本质上是成员函数的形式参数。 当对象调用成员函数时,将对象地址作为实参传递给this参数。 因此,this指针不存储在对象中。 this 指针是成员函数的第一个隐式指针参数。 一般由编译器通过寄存器自动传递,不需要用户传递。

this指针存储在哪里?

this指针是一个形参,一般存放在栈空间中。

这个指针可以为空吗?


class A
{
public:
	void Print()
	{
		cout <<"Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

程序运行正常。

成员函数放在公共代码区。 调用成员函数时无需取消引用该对象。 同时,成员函数内部不会访问成员变量,因此不会出现问题。

class A
{
public:
	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

程序运行错误:

程序运行过程中发生了空指针解引用,成员函数访问了对象的成员变量,但this指针却是空指针。

空指针取消引用会导致崩溃。

本章结束。

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码