C++: 类和对象(上)

📔个人主页📚: 秋邱-CSDN博客
☀️专属专栏✨: C++
🏅往期回顾🏆: 从C语言过渡到C++
🌟其他专栏🌟: C语言_秋邱

面向过程和面向对象

C 语言 被认为是面向过程的编程语言,在面向过程的编程中,重点在于程序功能的实现,通过函数调用逐步解决问题。

C++面向对象 的,编程强调的是将数据和对数据的操作封装在对象中,通过类和对象 的概念来组织程序结构,实现数据的隐藏、继承和多态等特性。

定义

是一种用户自定义的数据类型,它将数据(成员变量)和操作这些数据的函数(成员函数)封装在一起,形成一个逻辑上相关的单元。

cpp 复制代码
class 类名 {
    访问修饰符:
        成员变量;
        成员函数;
};

为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如成员变量前⾯或者后⾯加_或者m 开头,注意C++中这个并不是强制的,只是⼀些惯例,具体看公司的要求。

C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是 struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类。

注意:定义在类里面的成员函数默认为inline( 内联函数**)。**

访问限定符

C++ 实现封装的方式: 用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选

择性的将其接口提供给外部的用户使用。

C++ 中有有三种访问限定符:public(公共的),private(私人的),protected(受保护的)

  • public 修饰的成员在类外可以直接被访问
  • protectedprivate 修饰的成员在类外不能直接被访 问 ,protected和private是**⼀样的**
  • 访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有 访问限定符,作⽤域就到}即类结束。
  • class定义成员没有被访问限定符修饰时默认为private

cpp 复制代码
class Date
{
public://公开的
	void Init(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private://私有的
	int _year;
	int _month;
	int _day;
};

**拓展:**struct默认为public;

C 语言 中,对于结构体内部指针指向自身类型,需要使用 struct 关键字来标识 ,就像代码 1 中struct List* next;这样。而在C++ 中 ,可以直接使用结构体的名称 ,如代码 2 中的List* next; 。C++ 对结构体的处理方式更加灵活和方便,在结构体内部引用自身类型时无需再重复使用 struct关键字。

cpp 复制代码
//代码1,c语言的写法
struct List
{
	int val;
	struct List* next;
};

//代码2,c++的写法
struct List
{
	int val;
	List* next;
};

作用域

类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤::作 ⽤域操作符指明成员属于哪个类域。c++常用的四个域:局部域,全局域,命名空间域,类域。

cpp 复制代码
#include<iostream>
using namespace std;
class Date
{
public:
	//成员函数
	void Init(int year = 1, int month = 1, int day = 1);
private:
	//成员变量
	int _year;
	int _month;
	int _day;
};
//声明和定义分离,需要指定类域
//这里是☞Date这个类域下的Init函数
void Date::Init(int year = 1, int month = 1, int day = 1)
{
	_year = year;
	_month = month;
	_day = day;
}
int main()
{
	Date d1;
	d1.Init();
	return 0;
}

实例化

⽤类类型在物理内存中创建对象的过程,称为类实例化:

  • 类是对象进⾏⼀种抽象描述 ,是⼀个模型⼀样的东西,限定 了类有哪些成员变量 ,这些成员变量只是声明没有分配空间
  • ⽤类实例化出对象 时,才会分配空间
  • ⼀个类可以实例化出多个对象,实例化出的对象占⽤实际的物理空间,存储类成员变量。

就像建造一个房子之前需要设计图,设计完之后才能将房子建造出来(实例化),可以将这个设计的房子。

cpp 复制代码
int main()
{
//实例化出对象d1,d2,d3,d4
	Date d1;
	Date d2;
	Date d3;
	Date d4;
	return 0;
}

对象的大小

类和对象的内存对齐和struct几乎一模一样,对齐规则

  • 第⼀个成员 在与结构体偏移量为0的地址处
  • 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处
  • 注意:对⻬数=编译器默认的⼀个对⻬数与该成员⼤⼩的较⼩值。
  • 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍
  • 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。

如果还不清楚可以看看之前写的:C语言结构体

cpp 复制代码
#include<iostream>
using namespace std;
//含有成员函数和成员定义
class A
{
public:
	void print()
	{
		cout << " print()" << endl;
	}
private:
	char a1;
	int a2;
};
//含有成员函数
class	B
{
public:
	void print()
	{
		cout << " print()" << endl;
	}
};
//无
class C
{};
//嵌套
class D
{
public:
	class E{
		int b;
	};
private:
	int a;
};
int main()
{
	A a;
	B b;
	C c;
	D d;
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
	cout << sizeof(d) << endl;
	return 0;
}

c

上⾯的程序运⾏后,我们看到没有成员变量的B和C 类对象的⼤⼩是1 ,为什么没有成员变量还要给1个 字节呢?因为如果⼀个字节都不给,怎么表⽰对象存在过呢!所以这⾥给1字节,纯粹是为了占位标识 对象存在

D中 ,我们嵌套了E ,但是实际只有4个字节 ,这是因为嵌套类E的成员变量并不直接包含在类的内存布局中嵌套类是一个独立的类 ,它的成员变量的存储与外部类是相互独立的。

this指针

QiuQiu类中Print函数和默认构造函数,这两个成员中没有关于对象的区分,可为什么在调用时,却能够区分q1和请q2。其实这是C++在类中给了一个隐含的this指针来解决这里的问题。

编译器编译后,会在函数的第一个位置放置一个默认的成员函数,叫做this指针,且这个不需要我们手动去写。

C++规定不能在实参和形参 的位置显⽰的写this指针( 编译时编译器会处理),但是可以在函数体内显示使⽤this指针

cpp 复制代码
#include<iostream>
using namespace std;
class QiuQiu
{
public:
    //QiuQiu (QiuQiu* const this, int age, int height, int weight)
	QiuQiu (int age, int height, int weight)
	{
		_age = age;
		this->_height = height;
		this->_weight = weight;
	}
    //void Print(QiuQiu* const this)  --q1 /  q2
	void Print()
	{
		cout << "年龄:" << _age <<"岁" << endl;
		cout << "身高:" << _height << "厘米" << endl;
		cout << "体重:" << _weight << "千克" << endl << endl;;
	}

private:
	int _age;
	int _height;
	int _weight;
};
int main()
{
	QiuQiu q1(20,180,65);
	q1.Print();
	cout << endl;
	QiuQiu q2 (15,170,55);
	q2.Print();
	return 0;
}

注意this指针 跟普通指针一样都是放在区域上的。

小试牛刀

cpp 复制代码
下⾯程序编译运⾏结果是()
A、编译报错 B、运⾏崩溃 C、正常运⾏
#include<iostream>
using namespace std;
class A
{
public:
	void Print()
	{
		cout << "A::Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

A*p =nullptr;将p的地址就是this指针,而类中的成员函数放在公共代码段中,只是被类所限制访问。虽然表面上失去解引用,但printf()这个成员函数在编译的时候地址就以及确定了,之后只需要找到对应的函数即可,实际上并没有解引用。

cpp 复制代码
下⾯程序编译运⾏结果是()
A、编译报错 B、运⾏崩溃 C、正常运⾏
#include<iostream>
using namespace std;
class A
{
public:
	void Print()
	{
		cout << "A::Print()" << endl;
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

_a存在对象里面,p为空,this指针也就为空,对空指针进行解引用,会产生运行奔溃。

相关推荐
知识分享小能手1 分钟前
mysql学习教程,从入门到精通,SQL ORDER BY 子句(14)
大数据·开发语言·数据库·sql·学习·mysql·大数据开发
lkasi23 分钟前
python文字转wav音频
开发语言·python
kkk_皮蛋29 分钟前
力扣773:滑动谜题
c++
白茶等风1213833 分钟前
C#_封装详解
开发语言·c#
程序员阿鹏42 分钟前
ArrayList 与 LinkedList 的区别?
java·开发语言·后端·eclipse·intellij-idea
繁依Fanyi1 小时前
使用 Spring Boot + Redis + Vue 实现动态路由加载页面
开发语言·vue.js·pytorch·spring boot·redis·python·算法
星尘安全1 小时前
一种新的电子邮件攻击方式:AiTM
开发语言·网络安全·php·网络钓鱼·aitm
尘浮生1 小时前
Java项目实战II基于Java+Spring Boot+MySQL的洗衣店订单管理系统(开发文档+源码+数据库)
java·开发语言·数据库·spring boot·mysql·maven·intellij-idea
float_com1 小时前
【STL】 set 与 multiset:基础、操作与应用
c++·stl
鸽芷咕2 小时前
【Python报错已解决】xlrd.biffh.XLRDError: Excel xlsx file; not supported
开发语言·python·机器学习·bug·excel