C++ 【类和对象:this指针,构造函数 --1】

目录

1.类

1.2 类的访问限定符及封装

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

2.1 类的实例化

2.2 类对象的大小

3.this指针

4.类的6个默认成员函数

4.2 构造函数

4.3 构造函数的缺陷


1.类

C++将struct升级成为“类”,即使结构体,也是类。类中有:成员变量和成员函数

其中C++结构体内不仅可以定义变量,也可以定义函数(类中参数不需要传,可以直接访问)。

struct Stack
{
	int* a;
	int capacity;
	int top;

	void Init()
	{
		a = 0;
		top = capacity = 0;
	}

	void Push()
	{
		//
	}
};

int main()
{
	Stack s1;    
    s1.Init();
    s1.Push();
	return 0;
}

注:C++升级成类后,类名Stack同时也是类型


C++的用法(C语言中哪怕typedef内部还是要加struct)

struct ListNode
{
	ListNode* next;
	int val;
};

1.2 类的访问限定符及封装

 当换成class类后,再次编译发现说无法访问私有(private)

C++ 【类和对象:this指针,构造函数 --1】_第1张图片

这是因为:class的默认访问限定符权限为private,struct为public(因为struct要兼容C)

其中,访问限定符权限分为:公有(public),私有(private),保护(protected)

公有:类外/中可以访问  私有:只能在类中访问(保护与私有一样)

想给别人使用的定义成公有

class Stack
{
	int* a;
	int capacity;
	int top;
public:
	void Init()
	{
		a = 0;
		top = capacity = 0;
	}
private:

	void Push(int a)
	{
		//
	}
};

成员变量开始为私有,直到public成员函数变为公有,一直到结束(除非遇到下一个访问限定符,此时Push无法访问)

类也是一个域(花括号括起来就是一个域,一般影响的是编译器搜索规则)

一般默认类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:在类体外定义成员时,成员函数名前需要加类名::(方便阅读代码)

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

所以我们可以将小函数放到类中定义,大函数声明和定义分离,让定义和声明分离(成员函数就默认不是内联函数,同时也没办法在声明中加inline)

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

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


2.1 类的实例化

变量的声明和定义的区别:声明没开空间,定义开空间。声明只是告诉编译器有这个东西

用类型去定义一个对象的时候,才会开空间,叫做类的实例化(用类的类型创建对象的过程)

int top;//定义,全局变量

class Stack
{
	int* a;//声明,没开空间
	int capacity;
	int top;
};

int main()
{
	Stack s1;//类的实例化
	return 0;
}

类的注意事项:

1.类是对 “对象” 进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它(类不占空间),实例化出对象才占空间

2.类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间

class Person
{
private:
	char _name[20];
	char _gender[3];
	int _age;
};

int main()
{
	Person._age = 100;//报错
	return 0;
}

全局变量使用static改变的是连接属性仅在当前文件可见


2.2 类对象的大小

sizeof不计算成员函数的大小,只计算成员变量大小,实际就是该类中”成员变量”之和,注意内存对齐

class Mi
{
public:
	void fun()
	{
		cout << " Mi " << endl;
	}
	char a;
};
int main()
{
	cout<

 当类中只有成员函数时,占1个字节;空类的大小比较特殊,编译器给了空类一个字节来唯一标识这个类的对象

class Mi
{
public:
	void fun()
	{
		cout << " Mi " << endl;
	}
};

class Mi1
{};

int main()
{
	cout<

类对象的存储方式

对象里面只保存成员变量,成员函数存放在公共的代码段

以下函数的运行结果?

class Mi
{
public:
	void fun()
	{
		cout << " Mi " << endl;
	}
	char a;
};
int main()
{
	Mi* ptr = nullptr;
	ptr->fun();
	return 0;
}

该程序正常运行,原因在于调用fun,并不会去对象内部找成员函数,并没有去对空指针解应用,而是在编译链接(链接错误就是符号表找不到地址)时就根据函数名找到了函数的地址     


3.this指针

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

C++ 【类和对象:this指针,构造函数 --1】_第2张图片 下列为this指针隐藏的内容

this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。this指针只能在“成员函数”的内部使用

下列程序运行的结果是什么?

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

由于有this指针存在,其实传递过去了this指针,隐藏了this->_a,对空指针进行解应用,程序崩溃

this指针存在哪里?

默认存在栈区,偶尔也会存在寄存器上(当有很多成员变量时怕,频繁访问this指针,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递)。this指针本质上是“成员函数”第一个隐含的指针形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。 所以对象中不存储this指针


4.类的6个默认成员函数

任何类在什么都不写时,编译器会自动生成6个默认成员函数(用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数,一旦用户显式定义编译器将不再生成),它们分别为:

初始化和清理:构造函数--完成初始化   析构函数--完成清理工作

复制拷贝:拷贝构造--使用同类对象初始化创建对象   赋值重载--把一个对象赋值给另一个对象

+运算符重载

取地址重载:普通对象和const对象取地址


4.2 构造函数

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

创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次

如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

其特性:

1.函数名与类名相同。

2.无返回值(不用写void)

3.对象实例化时编译器自动调用对应的构造函数。

4.构造函数可以重载

5.参数看自己需要


普通初始化函数

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;
};

构造函数的性质

 1.保证对象实例化的时候一定被初始化

2.调全缺省的和无参的构造函数都可以,但是会导致歧义,所以一般第一第二个构造函数默认写一个

3.默认写一个全缺省参数(第二个函数)

4.如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明

class Date
{
public:
	Date()//无参构造函数
	{
		_year = 0;
		_month = 0;
		_day = 0;
	}
	Date(int year=0, int month=0, int day=0)//全缺省
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(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(2022, 7, 22); // 调用带参的构造函数
	//Date d2; // 调用无参构造函数
    Date d3(2000);

	return 0;
}


4.3 构造函数的缺陷

如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,但是实际我们不写构造函数却发现编译器并没有实际初始化对象

原因在于:C++把成员变量分为两种类型:1.内置类型(语言自带) 2.自定义类型 (struct/class类类型)

默认生成的构造函数对内置类型不做处理;对自定义类型进行处理,会去调用他的默认构造函数

任意类型的指针都属于内置类型,例如Time *_t(类型是解应用时意义)

这也就意味着,默认生成的构造函数对自定义类型无价值

举个例外,例如代码中MyQueue有价值(原因在于:类中的成员全是自定义类型才有价值)

MyQueue中没有写构造函数却被初始化,这是由于不写MyQueue构造函数的时候,对自定义类型会去调用它的默认构造函数(也依赖Stack构造函数)

C++ 【类和对象:this指针,构造函数 --1】_第3张图片

typedef int DataType;
class Stack
{
public:
	Stack(int capacity=4)
	{
		cout << "Stack(int capacity = 4)" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}

		_size = 0;
		_capacity = capacity;
	}

	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

class MyQueue
{
	Stack s1;
	Stack s2;
};

int main()
{
	Stack st;
	MyQueue q;
	return 0;
}

C++11打了补丁,允许在成员变量处赋值,不是初始化(这里还是声明),而是给编译器默认构造函数的缺省值(如果没有显示传参就用它们初始化,显示写了构造函数就没他事了)

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

 


以下三个都可以叫默认构造函数:

1.我们不写,编译器自动生成的那个

2.我们自己写的全缺省构造函数

3.自己写的无参构造函数

三个默认构造函数特点:不传参数就可以调用

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个,否则调用存在歧义

你可能感兴趣的:(C++,c++,开发语言)