【C++】——类和对象

这篇具有很好参考价值的文章主要介绍了【C++】——类和对象。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

面向过程和面向对象的初步认识

C语言是面向过程的,关注的是过程,分析求解问题的步骤,通过函数调用逐步解决问题
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成
C++不是纯面向对象的

【C++】——类和对象,c++

类的引入

C语言中,结构体内只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。(C++兼容C语言,结构体的用法可以继续使用,同时struct也升级成了类)
【C++】——类和对象,c++

struct Stack
{
	//成员函数
	void Init()
	{
		a = nullptr;
		top = capacity = 0;
	}

	//成员变量
	int* a;
	int top;
	int capacity;
};
void StackInit(struct Stack* ps)
{
	//....
}
int main()
{
	struct Stack st1;
	StackInit(&st1);


	Stack st2;
	st2.Init();
	return 0;
}

类的定义

class className
{
	//类体:由成员函数和成员变量组成

};//注意分号

struct和class最主要的区别就是访问限定符

1、类可以做声明和定义分离:
Test.cpp:
【C++】——类和对象,c++
Func.cpp:
【C++】——类和对象,c++
Func.h:
【C++】——类和对象,c++
2、类的两种定义方式:

1、声明和定义全部放在类体中,需要注意:成员函数如果在类中定义,编译器可以能会将其当成内联函数处理。函数不进入符号表。
2、类的声明放在.h文件当中,成员函数定义放在.cpp文件当中,注意:成员函数之前需要加类名。

类的访问限定符及封装

1、访问限定符:public protected private

C++实现封装的方式:用类将对象的属性和方法结合在一起,让对象更加完善,荣光访问权限选择性的将其接口提供给外部的用户使用。

1、public 修饰的成员在类外可以直接被访问
2、protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3、访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止
4、如果后面没有访问限定符,作用域到 } 结束
5、class的默认访问权限是private,struct为public(因为struct要兼容C)

#include <iostream>
using namespace std;
class Stack
{
public :
	//成员函数
	void Init()
	{
		a = nullptr;
		top = capacity = 0;
	}
	void push(int x)
	{
		if (top == capacity)
		{
			int newcapacity = capacity == 0 ? 4 : 2 * capacity;
			a = (int*)realloc(a, sizeof(int) * newcapacity);
			capacity = newcapacity;
		}
		a[top++] = x;
	}
	int Top()
	{
		return a[top - 1];
	}
private:
	//成员变量


	int* a;
	int top;
	int capacity;
};
int main()
{
	Stack st;
	st.Init();
	st.push(1);
	st.push(2);
	st.push(3);
	cout << st.Top() << endl;
	return 0;
}

2、C++中struct和class的区别是什么?

C++需要兼容C语言,所以C++中struct可以当成结构体使用,另外C++中struct还可以用来定义类。和class定义类是一样的。区别是:struct定义类的默认访问权限是public,class定义的类默认访问权限是private。

类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域

类的实例化

1、 用类类型创建对象的过程,称为类的实例化
2、类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。

【C++】——类和对象,c++

3、 一个类可以实例化出多个对象,类实例化出的对象占用实际的物理空间,类不占用实际的物理空间,存储类成员量。

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;    //是类的声明不是类的定义
	int _day;
};
int main()
{

	Date d;//实例化,开实际的物理空间
	d.Init(2023, 7, 21);
	return 0;
}

类在内存当中不占内存的空间,占文件系统的空间
类不能存储数据,类实例化的对象存储数据

【C++】——类和对象,c++
对象存储方式:
【C++】——类和对象,c++
【C++】——类和对象,c++
计算类的大小:

类中既有成员变量,又有成员函数

class A1 {
public:
	void f1() {}      //4
private:
	int _a;
};

类中仅有成员函数

class A2 {
public:
	void f2() {}        //1
};

类中什么都没有—空类

class A3       //1
{};

分配1字节,不存储数据,只是占位,表示对象存在过

结构体内存对齐规则:

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

this指针

class Date
{
public:
	void Init(int year, int month, int day)
	{
		cout << this << endl;
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << this << endl;
		cout << _year << "-" << _month << "-" << _day << endl;
	} 
private:
	int _year; 
	int _month;
	int _day;
};
int main()
{
	Date d1, d2;
	d1.Init(2022, 1, 11);
	d2.Init(2022, 1, 12);
	d1.Print();
	d2.Print();
	return 0;
}

此段代码中还隐含了this指针,在编译器中,编译器会默认给代码加上隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

【C++】——类和对象,c++

上述程序代码中,两个成员函数的指针并不是同一个,更准确的来说,是看this指针指向哪个对象,如何指向的是d1对象,那么调用两个成员函数的地址就是相同的。如果同时调用两个对象所指向的成员函数,那么this指针的地址就是不同的。
this指针指向当前调用的对象,是临时变量,函数调用结束后就销毁了

练习题1:

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

运行成功,打印Print( ),该函数存放在公共代码区,不存到成员变量中,所以p指针不解引用,运行成功

练习题2:

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

运行崩溃,此处有空指针的解引用,因为函数存放在公共代码区,p指针不解引用是空,同时this指针也是空,导致程序运行崩溃

this指针存放在哪?

this指针是一个形参,一般存在栈栈帧中。VS下面一般会用ecx寄存器直接传递

this指针的特性

  1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
  2. 只能在“成员函数”的内部使用
  3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
  4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

类的6个默认成员函数

如果一个类当中什么都没有,那么这个类就是空类,但是空类在什么都不写的情况下会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
默认构造函数的特点:不传参就可以调用的构造就是默认构造

class classmate
{

};

【C++】——类和对象,c++

构造函数

特性:构造函数是特殊的成员函数,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

特性:
1、函数名与类名相同
2、无返回值 (也不需要写void)
3、对象实例化时编译器自动调用对应的构造函数
4、构造函数可以重载 (可以写多个构造函数,提供多种初始化方式)

class Date
{
public:
	Date()//无参构造函数
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	Date(int year, int month, int day)//有参构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	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;
};

上述构造函数也可以合并写成参数全缺省形式

class Date
{
public:
	//Date()//无参构造函数
	//{
	//	_year = 1;
	//	_month = 1;
	//	_day = 1;
	//}
	//Date(int year, int month, int day)//有参构造函数
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	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;
	d1.Print();
	Date d2(2023,7,28);
	d2.Print();
	Date d3(2023, 7);
	d3.Print();
	/*d1.Init(2022, 7, 5);
	d1.Print();
	Date d2;
	d2.Init(2022, 7, 6);
	d2.Print();*/
	return 0;
}

C++实现栈:

#include <assert.h>

class Stack
{
public:
	/*Stack()
	{
		a = nullptr;
		top = capacity = 0;
	}*/

	Stack(size_t n = 4)
	{
		if (n == 0)
		{
			a = nullptr;
			top = capacity = 0;
		}
		else
		{
			a = (int*)malloc(sizeof(int) * n);
			if(a == nullptr)
			{
				perror("realloc fail");
				exit(-1);
			}

			top = 0;
			capacity = n;
		}
	}

	// 成员函数
	//void Init()
	//{
	//	a = nullptr;
	//	top = capacity = 0;
	//}

	void Push(int x)
	{
		if (top == capacity)
		{
			size_t newcapacity = capacity == 0 ? 4 : capacity * 2;
			int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				perror("realloc fail");
				exit(-1);//程序以异常的方式退出
			}
			if (tmp == a)
			{
				cout << capacity << "原地扩容" << endl;
			}
			else
			{
				cout << capacity << "异地扩容" << endl;
			}

			a = tmp;
			capacity = newcapacity;
		}

		a[top++] = x;
	}

	int Top()
	{
		return a[top - 1];
	}

	void Pop()
	{
		assert(top > 0);
		--top;
	}

	void Destroy()
	{
		free(a);
		a = nullptr;
		top = capacity = 0;
	}

	bool Empty()
	{
		return top == 0;
	}
private:
	// 成员变量
	int* a;
	int top;
	int capacity;
};

int main()
{
	Stack st1;
	st1.Push(1);
	st1.Push(2);
	st1.Push(3);
	st1.Push(4);
	
	while (!st1.Empty())
	{
		cout << st1.Top() << " ";
		st1.Pop();
	}
	cout << endl;

	st1.Destroy();

	//Stack st2(1000);
	Stack st2;
	for (size_t i = 0; i < 1000; i++)
	{
		st2.Push(i);
	}

	while (!st2.Empty())
	{
		cout << st2.Top() << " ";
		st2.Pop();
	}
	cout << endl;

	st2.Destroy();
}

推荐在一个类当中使用全缺省构造函数
构造函数,也是默认成员函数,我们不写,编译器会自动生成
编译生成的构造函数的特点:
1、我们不写才会自动生成,我们写了就不会自动生成了
2、内置类型(基本类型 int double)成员不会处理,(C++11,声明支持给缺省值)
3、对于自定义类型的成员才会处理,会去调用这个成员的默认构造函数
如果类中没有显示定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义编译器将不再生成。
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个(多个并存会存在调用的二义性)。
注意:无参构造函数,全缺省构造函数,我们没有写编译器默认生成的构造函数,都可以认为时默认构造函数(不传参就可以调用的)。
一般情况下都需要我们自己写构造函数,决定初始化方式

class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
int main()
{
	//MyQueue mq;
	Time t;
	return 0;
}

举例:

class A
{
public:
	A(int a)
	{
		cout << "A(int a)" << endl;
	}
private:
	int _a;
};
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;

	A _aa;

};
int main()
{
	Date d1;
	//Date d2(2023, 7, 29);
	return 0;
}

运行报错:
【C++】——类和对象,c++

错误原因:类A中不存在默认构造函数,默认构造函数:无参的构造函数和全缺省的构造函数。

代码更正:将类A中的构造函数写成参数全缺省形式

class A
{
public:
	A(int a=1)
	{
		cout << "A(int a)" << endl;
	}
private:
	int _a;
};
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;

	A _aa;

};
int main()
{
	Date d1;
	//Date d2(2023, 7, 29);
	return 0;
}

析构函数

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

特性:
1、析构函数名是在类名前加上字符“~”
2、无参数无返回值类型
3、一个类只能有一个析构函数,若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
4、对象生命周期结束时,C++编译系统自动调用析构函数
默认的析构函数:
对内置类型成员不做处理
自定义类型的成员会去调用他的析构函数

class Time
{
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
	~Time()
	{
		cout << "~Time()" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
int main()
{
	
	Time t;
	return 0;
}

栈需要显式的写析构函数

class Stack
{
public:
	//构造函数
	Stack(size_t n = 4)//unsigned int
	{
		if (n == 0)
		{
			a = nullptr;
			top = capacity = 0;
		}
		else
		{
			a = (int*)malloc(sizeof(int) * n);
			if (a == nullptr)
			{
				perror("malloc fail");
				exit(-1);//异常
			}
			top = 0;
			capacity = n;
		}
	}
	int Top()
	{
		return a[top - 1];
	}
	void Pop()
	{
		assert(top > 0);
		top--;
	}
	void Push(int x)
	{
		if (top == capacity)
		{
			size_t newcapacity = capacity == 0 ? 4 : capacity * 2;
			int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				perror("realloc fail");
				exit(-1);
			}
			if (tmp == a)
			{
				cout << capacity << "原地" << endl;
			}
			else
			{
				cout << capacity << "异地" << endl;
			}
			a = tmp;
			capacity = newcapacity;
		}
		a[top++] = x;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(a);
		a = nullptr;
		top = 0;
		capacity = 0;

	}
	bool Empty()
	{
		return top == 0;
	}
private:
	int* a;
	int top;
	int capacity;
};
int main()
{
	Stack st1(1000);
	st1.Push(1);
	st1.Push(2);
	while (!st1.Empty())
	{
		cout << st1.Top() << endl;
		st1.Pop();
	}
	return 0;
}

【C++】——类和对象,c++

默认析构函数:
1、内置类型成员不会处理
2、自定义类型成员会调用这个成员的析构函数

C++实现括号匹配文章来源地址https://www.toymoban.com/news/detail-620321.html

#include <iostream>
#include <assert.h>
using namespace std;

class Stack
{
public:
	Stack(size_t n = 4)//构造函数
	{
		cout << "Stack(size_t n = 4)" << endl;

		if (n == 0)
		{
			a = nullptr;
			top = capacity = 0;
		}
		else
		{
			a = (int*)malloc(sizeof(int) * n);
			if (a == nullptr)
			{
				perror("realloc fail");
				exit(-1);
			}

			top = 0;
			capacity = n;
		}
	}

	~Stack()//析构函数
	{
		cout << "~Stack()" << endl;
		free(a);
		a = nullptr;
		top = capacity = 0;
	}

	void Push(int x)
	{
		if (top == capacity)
		{
			size_t newcapacity = capacity == 0 ? 4 : capacity * 2;
			int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				perror("realloc fail");
				exit(-1);
			}
			if (tmp == a)
			{
				cout << capacity << "原地扩容" << endl;
			}
			else
			{
				cout << capacity << "异地扩容" << endl;
			}

			a = tmp;
			capacity = newcapacity;
		}

		a[top++] = x;
	}

	int Top()
	{
		return a[top - 1];
	}

	void Pop()
	{
		assert(top > 0);
		--top;
	}

	void Destroy()
	{
		free(a);
		a = nullptr;
		top = capacity = 0;
	}

	bool Empty()
	{
		return top == 0;
	}
private:
	// 成员变量
	int* a;
	int top;
	int capacity;
};
bool isValid(const char* s) {
	Stack st;
	while (*s)
	{
		if (*s == '[' || *s == '(' || *s == '{')
		{
			st.Push(*s);
			++s;
		}
		else
		{
			// 不匹配
			if (st.Empty())
				return false;

			char top = st.Top();
			st.Pop();

			// 不匹配
			if ((*s == ']' && top != '[')
				|| (*s == ')' && top != '(')
				|| (*s == '}' && top == '{'))
			{
				return false;
			}

			++s;
		}
	}

	return st.Empty();
}

int main()
{
	// 后定义,先析构
	

	Stack st1;
	Stack st2;

	cout << isValid("[[]]()()") << endl;
	cout << isValid("[[]]]") << endl;


	return 0;
}

到了这里,关于【C++】——类和对象的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】类和对象(四)

    前言:在类和对象中,我们走过了十分漫长的道路,今天我们将进一步学习类和对象,类和对象这块荆棘地很长,各位一起加油呀。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:高质量C++学习 👈 💯代码仓库:卫卫周大胖的学习日记💫 💪关注博主和博主一起学习

    2024年02月19日
    浏览(34)
  • 【C++】:类和对象(1)

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关C++中类和对象的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 目录 1.面向过程和面

    2024年02月08日
    浏览(37)
  • 【C++】类和对象(上)

    个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C++之路】 C语言是面向过程的,而C++是面向对象的,那面向过程和面向对象到底是什么呢? 我们拿一个非常典型的 外卖系统 来进行举例: 面向过程: 我们知道外面

    2024年02月02日
    浏览(45)
  • 【C++】类和对象(3)

    首先我们先回顾一下构造函数,对象的初始化由构造函数来完成,我们可以在构造函数的函数体内对对象的成员变量进行赋值,但这就有一个问题,如下: 答案:显然不是,因为变量只能定义一次。 也就是说,构造函数的函数体内部并不是初始化的地方(定义的地方),而

    2024年02月06日
    浏览(34)
  • 【C++】类和对象(下)

    在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化, 构造函数体中的语句只能将其称为赋初值 ,而不能称作初始化。因为初始化只能

    2024年03月25日
    浏览(49)
  • 【C++】类和对象(一)

    C++对C语言的补充最重要的功能之一就是类和对象的引入,在学习完漫长的C语言,从这里就算是开始踏上了高级语言之路,C++的这门语言有太多细节了,所以也要花费更多的时间和更多的精力,去面对更多的困难,做好心里准备,学校杂七杂八的事情,想要让学习和生活上的

    2024年02月05日
    浏览(29)
  • C++类和对象(上)

    ✨Blog:🥰不会敲代码的小张:)🥰 🉑推荐专栏: C语言 🤪、 Cpp 😶‍🌫️、 数据结构初阶 💀 💽座右铭:“ 記住,每一天都是一個新的開始😁😁😁 ” 💀本章内容: 《C++类和对象(上)》的介绍✨ C语言是面向过程的,关注的是过程,分析出求解的步骤,通过函数逐步解

    2024年01月25日
    浏览(38)
  • C++类和对象练习

    要求: (1)包含成员变量 m_a(立方体边长)。 (2)包含函数 SetA(doublea)(设置立方体边长)、GetVolume()(计算体积)、GetArea()(计算表面积)。 (3)包含函数 Display(),用来输出计算的结果。 (4)设计测试用主函数 main(),用来测试 Box 类。 包括: (1)普通数据成员:姓

    2023年04月18日
    浏览(40)
  • 【C++】类和对象-友元

    不在类外定义成员函数:

    2024年02月15日
    浏览(39)
  • c++学习——类和对象

    类是自定义数据类型,是C语言的结构体进化而成的 对象是类实例化出的,用数据类型定义一个变量 C和C++中struct区别: C语言struct只有变量 C++语言struct既有变量,也有函数 1、为什么要有封装? 封装是把属性(变量)和方法(函数)封装到类内,然后给这些数据赋予权限,防

    2024年02月07日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包