C++类和对象(上) 需c基础 超详细!!!

在最开始,总共分为上 、中、 下三章,循序渐进一点点理解;如果是有些部分看不懂可以去看看—>入门篇c++

1. 类的定义

  1. class是类的关键字,jojo为类的名字,{ } 内是类的主体,结束符号后面的分号一定不能省略。类体中的内容是成员:类中的变量为类的属性或者成员变量,类中的函数为类的方法或者叫成员函数;
  2. 最开始可以理解和C语言的stack很相似;了解完基础信息,再来讲讲 访问限定符,一便更好的了解类
#include <iostream>
#include <stdlib.h>
using namespace std;
class jojo
{
public:
	void STPush()
	{

	}
    void Top()
    {

    }
    // 成员函数       
    void Init(int n = 4)
    {
        int* array = (int*)malloc(sizeof(int) * n);
        if (nullptr == array)
        {
            perror("malloc 申请空间失败");
            return;
        }
        capacity = n;
        top = 0;
    }
private:
    //成员变量
	int* a;
	int top;
	int capacity;
    void Pop()
    {

    }
}; // 此处分号不能省略
int main()
{
    jojo st;
    st.Top();
    st.Init();

    //st.Pop(); //访问权限不够,和访问结构体的方法类似
    
	return 0;
}

3.为了区分成员变量,会加上一些特殊符号告诉你这个是成员变量,一般都会加上 " _ " 或者 m开头的或者其他的,在C++中并没有明确规定,都是看公司的或者个人喜好,不过java里面是有明确命名规定的

class Data
{
public:
    void time(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    jojo st;
    st.Top();
    st.Init();

    //st.Pop(); //访问权限不够,和访问结构体的方法类似
    Data t;
    t.time(2024, 7, 21);
	return 0;
}
  1. C++中的struct也可以用来定义类了,C++继续兼容C语言的用法,同时struct升级成为类,最主要的变化是struct中可以定义函数,不过更加推荐用class
    1. 如果要访问类里面的成员函数需要Data_2::time(int year, int month, int day)才可以使用成员函数,只是声明和定义分离了;
    2. 如果不指定类域Data_2 :: 这个,它去全局找就会找不到,本质上{}括起来的都会形成一个域
    3. C++,类名代表类型,直接可以表示类型可以不用向C语言一样重新取名
  2. 类里面声明的time函数,写在外面;叫做声明和定义的分离,time成员函数会受到类域影响

struct Data_2
{
public:
    void time(int year, int month, int day);
private:
    int _year;
    int _month;
    int _day;
};

//类里面声明的time函数,写在外面;叫做声明和定义的分离,time成员函数会受到类域影响
void Data_2::time(int year, int month, int day)  
{
    _year = year;
    _month = month;
    _day = day;
}

//C语言
typedef struct Queue
{
    int val;
    struct Queue* next; // C语言要这么写,是因为不知道类型
}Qu;// typedef ,是给他重新取一个名字,不用写冗长的typedef struct Queue,C++ 的Queue直接可以表示类型

// CPP 
struct Queue  //C++,类名代表类型
{
    int val;
    Queue* next;//这里指向的下一个节点不用在写struct了,直接和struct Queue* next;效果一样
};

1.1. 类定义格式

  1. class是类的关键字,jojo为类的名字,{ } 内是类的主体,结束符号后面的分号一定不能省略。类体中的内容是成员:类中的变量为类的属性或者成员变量,类中的函数为类的方法或者叫成员函数;
  2. 最开始可以理解和C语言的stack很相似;了解完基础信息,再来讲讲 访问限定符,一便更好的了解类

#include <iostream>
#include <stdlib.h>
using namespace std;
class jojo
{
public:
	void STPush()
	{

	}
    void Top()
    {

    }
    // 成员函数       
    void Init(int n = 4)
    {
        int* array = (int*)malloc(sizeof(int) * n);
        if (nullptr == array)
        {
            perror("malloc 申请空间失败");
            return;
        }
        capacity = n;
        top = 0;
    }
private:
    //成员变量
	int* a;
	int top;
	int capacity;
    void Pop()
    {

    }
};
int main()
{
    jojo st;
    st.Top();//这里是通" . ",可以访问到该对象的函数
    st.Init();

    //st.Pop(); //访问权限不够,和访问结构体的方法类似
    
	return 0;
}

3.为了区分成员变量,会加上一些特殊符号,告诉你这个是成员变量,一般都会加上 " _ " 或者 m开头的或者其他的,在C++中并没有明确规定,都是看公司的或者个人喜好,不过java里面是有明确命名规定的

class Data
{
public:
    void time(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    jojo st;
    st.Top();
    st.Init();

    //st.Pop(); //访问权限不够,和访问结构体的方法类似
    Data t;
    t.time(2024, 7, 21);
	return 0;
}
  1. C++中的struct也可以用来定义类了,C++继续兼容C语言的用法,同时struct升级成为类,最主要的变化是struct中可以定义函数,不过更加推荐用class
    1. 如果要访问类里面的成员函数需要Data_2::time(int year, int month, int day)才可以使用成员函数,只是声明和定义分离了;
    2. 如果不指定类域Data_2 :: 这个,它去全局找就会找不到,本质上{}括起来的都会形成一个域
    3. C++,类名代表类型,直接可以表示类型可以不用向C语言一样重新取名
struct Data_2
{
public:
    void time(int year, int month, int day);
private:
    int _year;
    int _month;
    int _day;
};
void Data_2::time(int year, int month, int day)
{
    _year = year;
    _month = month;
    _day = day;
}

//C语言
typedef struct Queue
{
    int val;
    struct Queue* next; // C语言要这么写,是因为不知道类型
}Qu;// typedef ,是给他重新取一个名字,不用写冗长的typedef struct Queue,C++ 的Queue直接可以表示类型

// CPP 
struct Queue  //C++,类名代表类型
{
    int val;
    Queue* next;//这里指向的下一个节点不用在写struct了,直接和struct Queue* next;效果一样
};
  1. 定义在类里面的成员函数都是默认为内联函数(inline):成员函数声明和定义分离就不是内联函数了,不过也不影响,inline只是对编译器的建议,会不会建立栈帧取决于编译器

1.2. 访问限定符

  1. ++用类将对象的属性与方法结合在一起,相当于封装起来了,让对象更加完善,通过访问权限,选择性的提供接口给外部使用。
  2. public(公有)修饰的成员在类外可以使用;protected(保护) private(私有)修饰的成员在类的外面不能被直接访问,目前阶段只需要用public和private就行了,后面涉及到 (继承)。
  3. 访问权限作用域,从当前访问限定符到下一个访问限定符,如果没有访问限定符,作用域就到 } 为止
  4. class 定义的成员没有访问限定符修饰,则默认是privatestruct 默认是public;可以从图中看出,class是默认为private的

1.3. 类域

  1. 类的定义会产生新的域,类的所有成员都在类的作用域中,在类体外定义成员需要使用 : : 指定类域符号声明和定义分离需要指定类域
  2. 类里面时声明,类外面是定义,声明不开辟空间定义会开辟空间

  3. 除了类域还有,全局域和局部域、命名空间域;类域不会影响生命周期,会隔离名字的查找,更改编译器的查找规则
  4. 编译器查找对应函数和定义时默认先查找局部然后是全局,没找到就会报错,如果要查找类域就需要指定

2. 实例化

2.1. 实例化概念

  1. 使用类的类型在物理内存中创建对象的过程,成为类实例化出对象
  2. 类就当相当于是设计图纸,可以做出模具、房子、机器等等;假如说有了房屋设计图纸,设计图纸有房间的厕所的客厅的,利用这个图纸可以建出很多房子
  3. 类就像设计图纸一样,类只是声明没有开辟空间,而房子设计图也一样不能住人,只有实例化出对象才会分配物理内存存储数据,房子也就可以住人了
  4. 类和对象是一对多的关系

#include <iostream>
using namespace std;
class Data
{
public:
    void time(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()
{
    Data d1;
    Data d2;
    d1.time(2024, 7, 1);
    d1.Print();
    d2.time(2024, 4, 1);
    d2.Print();
    return 0;
}

2.2. 对象大小

  1. 类可以实例化出对象,那么对象的大小是多少呢?首先可以知道对象中肯定包含成员变量的,那么是否包含成员函数呢?函数被编译后是一条指令,对象无法存储,所以成员函数是存储在代码块的
  2. 如果硬要存储呢?也不是不可以那就只能存储函数的指针了,但是函数调用1000次呢?那我是不是要存1000个函数指针,这样岂不是很浪费空间
  3. 函数指针是不用存储的,函数指针是一个地址,在调用函数的时候会被编译成汇编指令(call地址),编译器在编译时链接的,就要找到函数地址,不是在运行时找,只有多态运行时找

2.2.1. 内存对齐规则

内存的对齐规则其实和结构体一样

  1. 第一个成员放在结构体偏移量为0的地方
  2. 剩下的成员变量要和默认对齐数比较大小,较小值放到地址的对应位置
    1. 注:VS的默认对齐数是 8
  3. 结构体的总大小:最大对齐数的整数倍,计算完后的大小,如果小于最大对齐数的整数倍,就要以整数倍为准
  4. 如果嵌套了结构体,就要对齐到自己结构体的最大对齐数的位置上;
class A
{
public:
	void Print()
	{
		cout << cha << endl;
	}
private:
	char cha;
	int i;
	short sl;
};
class B
{
public:
	void Print()
	{
		;
	}
};
class c
{
};
  • B 和 C类对象发现只有一个成员函数,难道大小是 0 吗?其实不是;大小是1;因为一个字节都不给怎么表示对象存在呢?所以这个只是为了标识对象存在
  • 到后面,这种只有成员函数的类有很多

  1. 为什么要内存对齐?不对齐不是更加节省空间吗?
  2. 因为CPU不是能随意读取数据的,每个机器都有默认读取的大小不一样,根地址总线有关系,假设是32根地址总线,那么就是以四个字节来访问
  3. 内存对齐是为减少CPU的访问次数,提高效率
  4. 而左边,第一次读4字节,但只要一个

3.this指针

  1. 下列类中有两个成员函数,函数体中有着不同的对象,那么是怎么区分的呢?,那么它是怎么访问d1 和 d2的;其实C++做了对应处理,隐含的传递了一个this指针解决问题
  2. 编译器编译后,类的成员函数默认都会在形参的第一个,添加一个当前类型的指针,就是说的这个this指针了,当前写的time函数真正的原型是void time(Data* const this,int year, int month, int day)
  3. 类成员内的函数访问变量,可以是this->_year 并赋值;
  4. C++规定在形参和实参部分不可以显示写出this指针,因为这些编译器都会做,但是函数体内可以用this指针访问;其实到现在就可以解释前面的一些小疑惑,它是怎么访问参数的?
#include <iostream>
using namespace std;
class Data
{
public:
	//void time(Data* const this,int year, int month, int day)
	void time(int year, int month, int day)
	{
		//在成员函数内可以使用this指针来访问
		this->_year = year;
		this->_month = month;
		this->_day = day;
        //可以省略写成 _day = day;
	}
	//void Print(Data* const this)
	void Print()
	{
		cout << this->_year << '-' << this->_month << '-' << this->_day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Data d1;
	Data d2;
	//di.time(&d1,2024, 7, 1); 这里会隐式传递一个this指针
	d1.time(2024, 7, 1);
	//d1.Print(&d1);
	d1.Print();
	//d2.time(&d2,2024, 4, 1);
	d2.time(2024, 4, 1);
	//d2.Print(&d2);
	d2.Print();
}

小提问:this指针存在内存哪个区域的()

存在内存中的栈,从底层来看是进行了压栈的操作

继续加油!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值