C++ const在类中的扩展【C++】(zb)

const在类中的扩展

C++引入的面向对象的概念之后,C 语言中的一些比如 static/const 等原有语意,作一些升级处理,此时既要保持兼容,还要保持不冲突。

const 修饰数据成员

const 修饰数据成员,称为常数据成员,可能被普通成员函数和常成员函数来使用, 不可以更改。 C++中const必须初始化 可以在类中(不推荐),或初始化参数列表中(这是在类对象生成之前唯一的一次改变 const 成员值的机会了)

const 修饰数据成员不初始化存在的问题

我们先给出一个类内私有数据的const类型:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass()
	{

	}
	~MyClass()
	{

	}

private:
	const int x;
};


int main()
{
	MyClass a;
	return 0;
}

这个时候编译会出现问题:
在这里插入图片描述注意:
const 修饰类数据成员必须要初始化,我们在类内数据没有初始化,在构造器内也没又进行初始化,即使我们自己不在构造器里面进行初始化,那么系统默认自带的构造器也是一个无参空体构造器,也不会初始化。

那么并不是我们在构造器里面进行初始化之后,编译就能通过。
例如:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass()
	{
		x = 100;
	}
	~MyClass()
	{

	}

private:
	const int x;
};


int main()
{
	MyClass a;
	return 0;
}

这个时候也不能编译通过:

编译器会提示:
在这里插入图片描述

解决上述问题的const数据成员初始化方式

定义的时候初始化

我们把上面的x进行初始化编译就可以通过:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass()
	{
		x = 100;
	}
	~MyClass()
	{

	}

private:
	const int x = 100;
};


int main()
{
	MyClass a;
	return 0;
}

但是我们在平时的使用过程,在类对象中我们不建议这样的使用方法,我们希望一个对象的数据成员在初始的时候没有值,然后通过构造器进行构造,或者其他方式传递我们所需要的值。上面的const int生成的100放在了我们之后使用的每一个类对象里面,这是很不合适的。

通过对象传递参数使用参数列表进行初始化

#include <iostream>
using namespace std;
class MyClass
{
public:
	MyClass(int i):x(i)
	{}
	~MyClass()
	{}
	void dis()
	{
		cout << x << endl;
	}
private:
	const int x;
	int y;
};

int main()
{
	MyClass a(666);
	a.dis();
	return 0;
}

运行结果为:

在这里插入图片描述

这也是唯一的一次可以初始化的机会,
也就是说const修饰的数据成员可以在非const函数中使用,但是不可以更改。

通过初始化形参列表进行初始化

除了我们在类内定义类内数据的时候直接初始化,我们还可以在初始化列表进行初始化。

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass():x(100)
	{
		cout << "const x" << x << endl;
	}
	~MyClass()
	{

	}

private:
	const int x;
};
int main()
{
	MyClass a;
	return 0;
}

运行结果为:
在这里插入图片描述

初始化参数列表,提高了效率。

初始化参数列表如何提高效率

我们通过举例进行说明:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass() :x(100), y(200)
	{
		cout << "const x" << x << endl;
	}
	~MyClass()
	{

	}

private:
	const int x;
	int y;
};
int main()
{
	MyClass a;
	return 0;
}

我们上面的y初始化是在类对象创建的时候被初始化。
我们换一种方式进行初始化:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass() :x(100)
	{
		this->y = 200;
		cout << "const x" << x << endl;
	}
	~MyClass()
	{

	}

private:
	const int x;
	int y;
};
int main()
{
	MyClass a;
	return 0;
}

上面我们使用this指针进行初始化,this指针发生在对象创建完成之后。
我们再给出修改:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass() :x(100),this->y(200)
	{
		this->y = 200;
		cout << "const x" << x << endl;
	}
	~MyClass()
	{

	}

private:
	const int x;
	int y;
};
int main()
{
	MyClass a;
	return 0;
}

上面代码编译器会报错:

在这里插入图片描述

无this标识符,那么说明类对象在创建的时候是没有生成this指针的。
所以使用初始化参数列表进行初始化效率更高。

初始化参数列表拓展

除了提高效率,也可以为一些新扩展的功能提供一个解决场所或者办法

举例进行:我们在使用的过程中也会对类内数据使用引用
我们在数据成员引用z

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass():x(100),y(200)
	{
		cout << "const x" << x << endl;
	}
	~MyClass()
	{

	}
private:
	const int x;
	int y;
	int& z;
};
int main()
{
	MyClass a;
	return 0;
}

编译不能通过:

编译器会提示
在这里插入图片描述

这里的未提供初始值设定项就是引用。

那么我们就需要引用到类内:

#include <iostream>

using namespace std;

class MyClass
{
public:
	MyClass(int & zz):x(100),y(200),z(zz)
	{
		cout << "const x" << x << endl;
		cout <<z<< endl;
	}
	~MyClass()
	{

	}
private:
	const int x;
	int y;
	int& z;
};


int main()
{
	int z = 300;
	MyClass a(z);
	return 0;
}

我们就通过形参列表使用引用让类内使用类外数据。
运行结果为:
在这里插入图片描述

那么向上面

const  int    x;
int &z ;

的问题在我们之前学习struct里面是没有的。

const 修饰函数成员

const 修饰函数的位置

const 修饰函数放在,声明之后,实现体之前,大概也没有别的地方可以放了。

void dis() const

const 可以修饰全局函数吗?
const 修饰类成员函数,不可以修饰全局函数
读者可以自行验证

const 成员函数的意义

承诺在本函数内部不会修改类内的数据成员,为此,也只能调用承诺不会改变成员的其它 const 成员函数,而不能调用其它非 const 成员函数。

类内const函数不允许修改类内的数据成员

我们接下来对于上面的意义进行解释说明:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void dis() const
	{
		_x = 200;
		cout << _x << endl;
		cout << _y << endl;
	}


private:
	int _x;
	const int _y;
};
int main()
{
	A a(3,4);
	a.dis();
	return 0;
}

上面代码在运行的时候就会出现问题:

在这里插入图片描述
不允许在类内const对于类内数据成员的值进行修改。也就是承诺在本函数内部不会修改类内的数据成员。

类内const函数不允许调用能够修改类内数据成员的函数

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void dis() const
	{
		fun();
		cout << _x << endl;
		cout << _y << endl;
	}
	void fun()
	{
		_x = 200;
	}


private:
	int _x;
	const int _y;
};
int main()
{
	A a(3,4);
	a.dis();
	return 0;
}

上面代码编译器也会报错:

在这里插入图片描述

也就是说,不允许调用能够修改类内数据成员的函数。及就是只能调用承诺不会改变成员的其它 const 成员函数,而不能调用其它非 const 成员函数。

如果调用的都是const成员函数,就不会出现问题:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void dis() const
	{	
		cout << _x << endl;
		cout << _y << endl;
		fun();
	}
	void fun() const
	{
		cout << _x << endl;
		cout << _y << endl;
	}


private:
	int _x;
	const int _y;
};
int main()
{
	A a(3,4);
	a.dis();
	return 0;
}

运行结果为:
在这里插入图片描述

const 构成重载

接触过的const重载

我们在之前已经接触过const重载,例如:

#include <iostream> 
using namespace std;


int add(int & a, int & b)
{
	return a + b;
}

int main()
{
	int a = 4;
	int b = 4;
	cout << add(a, b) << endl;
}

运行结果为:

在这里插入图片描述
我们知道上面代码不管传递引用还是传值都没有问题。

我们对于上面代码进行修改:

#include <iostream> 
using namespace std;


int add(int & a, int & b)
{
	return a + b;
}

int main()
{
	int a = 4;
	int b = 4;
	cout << add(a, b) << endl;
	cout << add(4, 5) << endl;
}

那么上面代码就出现了问题:
在这里插入图片描述

因为4,5为常量,引用的时候是不允许把const int 常量引用为int 变量。

那么我们就需要在子函数形参加上const:

#include <iostream> 
using namespace std;


int add(const int & a, const int & b)
{
	return a + b;
}

int main()
{
	int a = 4;
	int b = 4;
	cout << add(a, b) << endl;
	cout << add(4, 5) << endl;
}

运行结果为:
在这里插入图片描述

那么如果我还想要通过函数进行值的修改,使用const就不能修改,
那我们就使用const重载,在想要修改值的时候就可以进行修改,不想要修改值的时候就不修改:

#include <iostream> 
using namespace std;


int add(int& a, int& b)
{
	cout << "not const" << endl;
	return a + b;
}
int add(const int & a, const int & b)
{
	cout << "const" << endl;
	return a + b;
}

int main()
{
	int a = 4;
	int b = 4;
	cout << add(a, b) << endl;
	cout << add(4, 5) << endl;
}

我们打印出调用函数的不同:
运行结果为:

在这里插入图片描述

上面就是使用了const重载。

C++类中的const重载

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void foo()
	{	
		cout << "void foo()" << endl;
		cout << _x << endl;
		cout << _y << endl;
	}
	void foo() const
	{
		cout << "void foo() const" << endl;
		cout << _x << endl;
		cout << _y << endl;
	}


private:
	int _x;
	const int _y;
};
int main()
{
	A a(3,4);
	a.foo();
	return 0;
}

运行结果为:

在这里插入图片描述

如果我们把void foo()函数进行注释:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	//void foo()
	//{	
	//	cout << "void foo()" << endl;
	//	cout << _x << endl;
	//	cout << _y << endl;
	//}
	void foo() const
	{
		cout << "void foo() const" << endl;
		cout << _x << endl;
		cout << _y << endl;
	}


private:
	int _x;
	const int _y;
};
int main()
{
	A a(3,4);
	a.foo();
	return 0;
}

运行结果为:
在这里插入图片描述

我们得出结论:
const构成的重载函数,非const对象调用,优先调用非const函数。

我们对于代码进行修改:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void foo()
	{	
		cout << "void foo()" << endl;
		cout << _x << endl;
		cout << _y << endl;
	}
	void foo() const
	{
		cout << "void foo() const" << endl;
		cout << _x << endl;
		cout << _y << endl;
	}


private:
	int _x;
	const int _y;
};
int main()
{
	const A a(3,4);
	a.foo();
	return 0;
}

运行结果为:
在这里插入图片描述

我们把const类内函数进行注释:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void foo()
	{	
		cout << "void foo()" << endl;
		cout << _x << endl;
		cout << _y << endl;
	}
	//void foo() const
	//{
	//	cout << "void foo() const" << endl;
	//	cout << _x << endl;
	//	cout << _y << endl;
	//}


private:
	int _x;
	const int _y;
};
int main()
{
	const A a(3,4);
	a.foo();
	return 0;
}

上面代码会编译出错。

我们得到结论:
const 修饰的对象,只能调用类内cosnt成员函数。
很多库常见提供两个版本

const inline static关键字使用注意

const

const 修饰的类内成员函数如果在class外进行实现的时候const也不能省略:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void foo();
	void foo() const;

private:
	int _x;
	const int _y;
};

void A::foo()
{
	cout << "void foo()" << endl;
	cout << _x << endl;
	cout << _y << endl;
}
void  A::foo() const
{
	cout << "void foo() const" << endl;
	cout << _x << endl;
	cout << _y << endl;
}
int main()
{
	const A a(3,4);
	a.foo();
	return 0;
}

const 关键在在声明和定义的时候都不能省略

static

static 关键字,只能在类内函数声明的时候出现,定义的时候不允许出现:

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	static void foo();

private:
	int _x;
	const int _y;
};

void A::foo()
{
}

int main()
{
	const A a(3,4);
	a.foo();
	return 0;
}

上面代码编译可以通过。

inline

inlint 类型关键字可以在函数声明处有,函数定义处没有。可以在函数声明处没有,在函数定义处有。也可以在函数声明和定义的时候都出现。当然,在函数声明和实现的地方都不出现那就和inline没有关系了。

const修饰对象

const 修饰对象,保证在对象层面,不会修改数据成员。所以 const 对象,只能调用 const 成员函数。不同编译器,可能会要求必须自实现构造器,因为若采用默认的话,const 对象的中成员,再无初始化的机会。

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}
	void dis()
	{
		cout << _x << _y << endl;
	}
private:
	int _x;
	int _y;
};

int main()
{
	const A a(3,4);
	a.dis();
	return 0;
}

上面代码编译会出现错误。

在这里插入图片描述

const修饰的对象,其内可以有非const数据成员,但是数据成员不可修改,只能调用const成员函数。

一般来说const修饰对象会提供const和非const两个版本,构成const重载

#include <iostream> 
using namespace std;
class A
{
public:
	A(int i,int j):_x(i), _y(j)
	{}

	void dis() const
	{

		cout << _x << _y << endl;
	}

	void dis() 
	{
		
		cout << _x << _y << endl;
	}
private:
	int _x;
	int _y;
};

void func(const A & a)
{
	a.dis();
}

int main()
{
	const A a(3,4);
	a.dis();
	func(a);
	return 0;
}

运行结果为:
在这里插入图片描述

总结

在这里插入图片描述

发布了163 篇原创文章 · 获赞 94 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43648751/article/details/104520583