我是靠谱客的博主 平常导师,最近开发中收集的这篇文章主要介绍C++基础--类与对象,this概念(上)1.面向过程和面向对象初步认识2.类的引入3.类的定义 4.类的访问限定及封装5.类的大小6.this指针,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.面向过程和面向对象初步认识

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

C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

例如:设计简单外卖系统

面向过程:关注实现下单、接单、送餐这些过程。具体到代码层面--方法/函数

面向对象:关注实现类对象及类对象的关系,用户、商家、骑手以及他们之间的关系。提现到代码层面--类的设计及类之间的关系。

  • C++基于面向对象:面向过程和面向对象混编。原因:C++兼容C
  • Java纯面向对象:只有面向对象。

2.类的引入

在C中定义一个结构用的是struct,在C++因为兼容C,所以也可定义一个结构体用struct,而C++中的类运用的关键字是struct和class

C++中struct升级成了类。C++类跟结构体不同是除了可以定义变量,还是可以定义方法/函数

定义一个Student的类

struct Student
{
	char name[10];
	int age;
	int id;
};

int main()
{
	struct Student s1;//兼容c
	Student s2;//升级到类,Student类名,也是类型


    //将s1赋值
    strcpy(s1.name, "张三");
	s1.id = 1;
	s1.age = 10;

	return 0;
}

C++的类中可以写函数,我们程它为成员方法/成员函数,他们当中定义的参数,我们成为成员变量

struct Student
{
    //成员变量
	char _name[10];
	int _age;
	int _id;
    
    //成员方法/成员函数
	void Init(const char* name, int age, int id)
	{
		strcpy(_name, name);
		_age = age;
		_id = id;
	}

	void Print()
	{
		cout << _name << endl;
		cout << _age << endl;
		cout << _id << endl;
	}
};

int main()
{
	struct Student s1;
	Student s2;

	s1.Init("张三", 18, 1);
	s2.Init("里斯", 19, 2);

	s1.Print;
	s2.Print;

	return 0;
}

类比于C中的写法,是将成员变量与成员方法分离开来,这就像一个松散的管理和一个严格的管理,C语言让函数与成员变量分离开来使得更加变通自由,而由此可能带来更多问题。C++为此改变C中的自由性而使用类来封装,使得管理和使用起来更加方便严格。

3.类的定义

C++中类更喜欢用class来代替struct

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

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。
类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。

类的两种定义方式

1.声明和定义全部放在类体中

【注意】:成员函数如果在类中定义,编译器可能会将其当作内联函数处理

2.声明放在.h中,类的定义放在.cpp文件中

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

类的其他形式

1.类中仅有成员变量

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

2.类中什么都没有--空类

class A3
{

};

 4.类的访问限定及封装

面向对象三大特性:封装、继承、多态

类的访问限定符

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

封装由两个注意事项:

  • 数据和方法都放到了一起在类里面
  • 访问限定符

 【访问限定符说明】

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

【问题】:

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

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

封装

【问题】:
在类和对象阶段,我们只研究类的封装特性,那什么是封装呢?

将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

5.类的大小

对象中包含的各个成员

 【问题】:

每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象都会保存一份代码,相同代码保存多次,浪费空间,那么如何解决呢?

只保存成员变量,成语那函数存放在公共代码段

 对象中存了成员变量,但是没存成员函数,成员函数放在公共区。每个对象都有独立的成员变量,不同对象调用成员函数是同一个。

存在公共区的成员函数并不参加对象大小计算,而是计算成员变量的大小,跟C语言的内存对其是一样的方法。

class Stack
{
public:
	void Init()
	{
		_a = nullptr;
		_top = _capacity = 0;
	}
	void Push(int x)
	{

	}
	int Top()
	{
		assert(_top > 0);
		return _a[_top - 1];
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

int main()
{
	Stack s;
	s.Init();

	cout << sizeof(Stack) << endl;
	cout << sizeof(s) << endl;

    return 0;
}

空类会给1byte,这1byte不存储有效数据,只是为了占位,表示对象存在

//类中仅有成员函数
class A2
{
public:
	void f2(){}
};

//类中什么都没有--空类
class A3
{

};

int main()
{
	Stack s;
	s.Init();

	A2 aa;
	A3 bb;

	cout << sizeof(aa) << endl;
	cout << sizeof(bb) << endl;
}

 结论:计算类或者类对象大小,只看成员变量,考虑内存对齐,C++内存对其规则跟着C结构体一致。

6.this指针

6.1this指针的引出

我们先来定义一个日期类Date

class Date
{
public:
	void Init(int year, int month, int day)
	{
		Date::year = year;
		_month = month;
		_day = day;
	}

private:
	int year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Init(2022, 1, 15);

	return 0;
}

这里的Date::year = year;如果不加Date变成year=year,那么两个地方调用的都是形参,前面的的year调用的不是成员变量,那我们除了用::指明作用域外,我们还可以用到一个方法,那就是this.但是为了避免对成员变量名字的混淆,我们还是避免写这种代码。

还有一个问题

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;
	d1.Init(2022, 1, 15);
	d1.Print();

	Date d2;
	d2.Init(2022, 1, 16);
	d2.Print();

	return 0;
}

在这段代码中,d1和d2两个实例化对象分别都调用了成员函数,函数体中没有关于不同对象的区分,我们直到,d1和d2的成员变量是不同的,但是他们调用的函数是公共区域的,那当d1调用Init()和Print()函数如何知道它是d1对象而不是d2对象呢

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

 可以看到调用的Print()函数是同一个地址,说明每次都调用公共区域里的成员函数。

d1.Print()中调用的是公共区域,这里隐藏了一个this指针,其实他的真面目是

class Date
{
public:
	void Init(Date* const this,int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	void Print(Date* const this)
	{
		//一般情况下,我们不会像下面这样写
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Init(&d1,2022, 1, 15);
	d1.Print(&d1);

	Date d2;
	d2.Init(&d2,2022, 1, 16);
	d2.Print(&d2);

	return 0;
}

但是实际中并不能这么写,这里this遵循几个原则:

  • 调用成员函数时,不能显示传实参给this
  • 定义成员函数时,不能显示声明形参this
  • 在成员函数内部,我们可以显示使用this

也就是说上述代码最多只能写成这样

class Date
{
public:
	//void Init(Date* const this,int year, int month, int day)
	void Init(int year, int month, int day)

	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	//void Print(Date* const this)
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
		//一般情况下,我们不会像下面这样写
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

【注意】:

这里实际上成员函数里this需要加const,这意味着this本身不能被改变,为了防止写代码可能出现的意外。

【问题】:
this是存在哪?

一般情况下是存在栈(形参),在有些编译器中会放到寄存器中,如vs2013/19都会存放在ecx中

最后

以上就是平常导师为你收集整理的C++基础--类与对象,this概念(上)1.面向过程和面向对象初步认识2.类的引入3.类的定义 4.类的访问限定及封装5.类的大小6.this指针的全部内容,希望文章能够帮你解决C++基础--类与对象,this概念(上)1.面向过程和面向对象初步认识2.类的引入3.类的定义 4.类的访问限定及封装5.类的大小6.this指针所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部