C++类与对象深入之运算符重载与const及初始化列表详解

目录
  • 一:运算符重载
    • 相等运算符重载
    • 赋值运算符重载
    • 小于运算符重载
  • 二:const成员
    • const修饰类的成员函数
  • 三:cin、cout重载
  • 四:初始化列表
    • 构造函数赋初值
    • 初始化列表
    • explicit关键字

一:运算符重载

C++为了增强代码的可读性引入了运算符的重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型以及参数列表,其返回值类型与参数列表与普通函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号

函数原型:返回值类型 operator操作符(参数列表)

相等运算符重载

对内置类型我们想要判断两个变量是否相等我们可以直接使用相等运算符,但是如果是一个自定义类型呢?那么这时候就需要重载运算符了。

下面重载一个全局的 operator ==:

class Date
{
public:
	// 默认生成的析构函数,内置类型成员不做处理,自定义类型成员会去调用它的析构函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	int GetYear(){
		return _year;
	}
	int GetMonth(){
		return _month;
	}
	int GetDay(){
		return _day;
	}
private:
	int _year;
	int _month;
	int _day;
};
bool operator==( Date& d1,  Date& d2)
{
	return d1.GetYear() == d2.GetYear()
		&& d1.GetMonth() == d2.GetMonth()
		&& d1.GetDay() == d2.GetDay();
}
int main(){
	Date d1(2022, 5, 16);
	Date d2(2022, 5, 16);
	if (operator==(d1, d2)){
		cout << "==" << endl;
	}
	if (d1 == d2){ // 编译器会处理成对应重载运算符调用 if (operator==(d1, d2)){
		cout << "==" << endl;
	}
	system("pause");
	return 0;
}

我们把运算符重载成全局的时候,面对私有成员不可类外访问,我们提供三个函数接口,当然还有别的处理方式。我们可以上述“运算符重载可以判断两个自定义日期类是否相等

我们看到主函数中两处调用重载运算符,两种写法都可以,第二种方法更简单,编译器会自动处理成第一种方式。

我们还可以重载成类的成员函数,作为类成员重载函数时,其形参看起来比操作数目少1个

class Date
{
public:
	// 默认生成的析构函数,内置类型成员不做处理,自定义类型成员会去调用它的析构函数
	Date(int year = 1, int month = 1, int day = 1){
		_year = year;
		_month = month;
		_day = day;
	}
	void Print(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2022, 5, 16);
	Date d2(2022, 5, 16);
	if (d1.operator==(d2)){
		cout << "==" << endl;
	}
	if (d1 == d2){ // 编译器会处理成对应重载运算符调用 if (d1.operator==(d2))
		cout << "==" << endl;
	}
	system("pause");
	return 0;
}

”“解释:重载成成员函数的时候,成员函数里隐藏了this指针,形参列表其实是(Date * this, const Date & d2),函数调用时左操作数是this指针指向的对象!

同样地,我们看到主函数中两处调用重载运算符,两种写法都可以,第二种方法更简单,编译器会自动处理成第一种方式。

赋值运算符重载

C++编译器至少给一个类添加4个函数:

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝
  • 赋值运算符 operator=, 对属性进行值拷贝

赋值运算符主要有4点:

  • 参数类型
  • 返回值
  • 检查是否自己给自己赋值
  • 返回 *this

代码示例:

class Date
{
public:
	// 默认生成的析构函数,内置类型成员不做处理,自定义类型成员会去调用它的析构函数
	Date(int year = 1, int month = 1, int day = 1){
		_year = year;
		_month = month;
		_day = day;
	}
	void Print(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	// d2 = d1; -> d2.operator=(&d2, d1)
	// d1 = d1
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2022, 5, 16);
	Date d2;
	Date d3(d1); // 拷贝构造  -- 一个存在的对象去初始化另一个要创建的对象
	d2 = d1;     // 赋值重载/复制拷贝 -- 两个已经存在对象之间赋值
	d1 = d1;
	system("pause");
	return 0;
}

”“解释:类对象d1给d2赋值,特别注意赋值重载函数的返回值,和检查是否自己给自己赋值!

我们要区分拷贝构造和赋值重载:拷贝构造是一个存在的对象去初始化另一个要创建的对象,而赋值重载是两个已经存在对象之间赋值。

如下列监视列表我们可以看出,结果d1.d2,d3都是一样的。

正如一开始所说的,如果一个类中没有显示定义赋值运算符重载,编译器也会生成一个,完成对象的浅拷贝。既然是浅拷贝就有局限,如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。

小于运算符重载

下面我们比较日期类的大小:

代码示例:

class Date
{
public:
	// 默认生成的析构函数,内置类型成员不做处理,自定义类型成员会去调用它的析构函数
	Date(int year = 1, int month = 1, int day = 1){
		_year = year;
		_month = month;
		_day = day;
	}
	void Print(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	bool operator<(const Date& d){
	if ((_year < d._year)
	|| (_year == d._year && _month < d._month)
	|| (_year == d._year && _month == d._month && d._day < d._day))
	{
	return true;
	}
	else{
	return false;
	}
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2022, 4, 16);
	Date d2(2022, 5, 16);
	if (d1 < d2){ // 编译器会处理成对应重载运算符调用 if (d1.operator<(d2))
		cout << "<" << endl;
	}
	system("pause");
	return 0;
}
<
请按任意键继续. . .

二:const成员

const修饰类的成员函数

将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

//this指针的本质是一个指针常量,指针的指向不可修改

//如果想让指针指向的值也不可以修改,需要声明常函数

我们见下面一段代码:

void Func(const Date& d)
{
	d.Print(); // d.Print(&d); -> const Date*
	//传的是一个指针指向的内容不可以改变的指针,
	//而单纯的this指针是指向不可以改变,所以权限放大了  必须在Print函数后加const,把this指针权限进一步放小
	cout << &d << endl;
}
void TestDate3()
{
	Date d1(2022, 5, 18);
	d1.Print(); // d1.Print(&d1); -> Date*
	Func(d1);
	cout << &d1 << endl;
}

代码解释:如果Print不是常函数,那么在TestDate3()函数中调用Print函数不会报错,但是如果在Func函数中调用就会报错,这是因为在TestDate3()函数中调用Print函数传过去d1的地址,用this指针接收,权限缩小。而在Func函数中,d指针指向的内容不可以改变,而在形参this指向的内容可以改变,所以权限放大。所以必须给Print函数加上const,以表示常函数。

️️️️️️建议:

建议成员函数中不修改成员变量的成员函数,都可以加上const, 普通对象和const对象都可以调用。

三:cin、cout重载

我们都知道了cin、cout对于内置类型可以自动识别其类型进行输入输出,这是因为在库函数中提供了对应的重载!

下面我们直接看代码:

	class Date
{
public:
	// 友元函数
	friend std::ostream& operator<<(std::ostream& out, const Date& d);
	friend std::istream& operator>>(std::istream& out, Date& d);
	//........
}

首先我们定义成全局函数,必须在对应的类中声明友元,这样全局函数才可以访问类中成员!

std::ostream& operator<<(std::ostream& out, const Date& d)
{
	out << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}
std::istream& operator>>(std::istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

四:初始化列表

C++提供了初始化列表语法,用来初始化属性

构造函数赋初值

在创建对象的时候,编译器通过调用构造函数,给对象中各个成员变量一个合适的初值。

class Person {
public:
	Person(int a, int b, int c) {
		m_A = a;
		m_B = b;
		m_C = c;
	}
private:
	int m_A;
	int m_B;
	int m_C;
};
int main() {
	Person p(1, 2, 3);
	system("pause");
	return 0;
}

上述代码我们通过构造函数赋值的方法来“初始化”。

注意:上述代码中调用构造函数后,对象中已经有了一个初始值,但是我们不能将之称为类对象成员的初始化,只能称为赋值,因为初始化只可以初始化一次,而构造函数体内可以赋值多次

初始化列表

class Person {
public:
	//初始化列表方式初始化
	Person(int a, int b, int c)
		: m_A(a)
		, m_B(b)
		, m_C(c)
	{}
private:
	int m_A;
	int m_B;
	int m_C;
};
int main() {
	Person p(1, 2, 3);
	system("pause");
	return 0;
}

初始化列表:以一个冒号开始,以逗号分隔,每部分由成员变量后面跟上一个放在括号里的初始值或者表达式。

注意:

每个成员变量在初始化列表中只能出现一次(即初始化只一次)。

类中包含以下成员,就必须在初始化列表位置进行初始化。

  • 引用成员变量
  • const成员变量
  • 自定义类型成员(该类没有对应的默认构造函数)

我们这里先这么理解一下:初始化列表可以认为就是对象的成员变量定义的地方,对于上面的三种成员只能在定义初始化,而其他的内置类型变量,/可以在定义时初始化,也可以定义时不初始化,后面再赋值修改。

下面我们直接上代码:

int value = 10;
class A
{
public:
	A(int x)
		:_x(x)
	{}①
	/*A(int x = 0)
		:_x(x)
	{}*/②
private:
	int _x;
};
class Date
{
public:
	Date(int year, int n, int a)
		:_n(n)
		, _ref(value)
		,_aa(a)//①:当自定义类型没提供默认构造时,就在想用我们提供的值去初始化的时候,就在这里显式的去调用它的构造函数
		//如果有对应的默认构造,就不用写这行。不在初始化列表初始化,自动调用默认构造函数初始化
	{
		_year = year;
		//如果不在初始化列表初始化 ,但是我们还想去改变里面变量的值,只能这么玩
		//A aa(a);  调用默认构造 ②
		//_aa = aa;//赋值  这里使用了默认提供的赋值运算符重载?   这种方式麻烦  就用下面这种好
	}
private:
	int _year; // 声明
	const int _n;
	int& _ref;
	A _aa;
};
int main()
{
	Date d1(2022, 5, 20); // 对象定义
	system("pause");
	return 0;
}

代码解释:上述代码中,_n、_ref、_aa都是要在初始化列表初始化的变量,见代码注释

️️️:上面在初始化的时候都比较麻烦,因此我们建议尽量在初始化列表初始化,如下代码:

int value = 10;
class A
{
public:
	A(int x)
		:_x(x)
	{}
private:
	int _x;
};
class Date
{
public:
	Date(int year, int n, int a)
		:_n(n)
		, _ref(value)
		, _year(year)
		, _aa(a)//当自定义类型没提供默认构造时,就在这里显式的去调用它的构造函数
	{}
	//总结:建议尽量在初始化列表初始化
private:
	int _year; // 声明
	const int _n;
	int& _ref;
	A _aa;
};
int main()
{
	Date d1(2022, 5, 20); // 对象定义
	system("pause");
	return 0;
}

正如我们代码注释的地方所说,当自定义类型没提供默认构造时,我们又想用我们提供的值去初始化的时候,就需要我们去手动的调用它的构造函数,,,,,,

初始化结果如下:

如果有对应的默认构造函数,我们也可以不用写这行。这时候就不在初始化列表初始化,编译器自动调用默认构造函数初始化,初始化为随机值还是确定值要看是什么类型的默认构造函数。

int value = 10;
class A
{
public:
	A(int x = 10)//全缺省默认构造
		:_x(x)
	{}
private:
	int _x;
};
class Date
{
public:
	Date(int year, int n, int a)
		:_n(n)
		, _ref(value)
		, _year(year)
		//, _aa(a)  这时候我们在A类中提供了全缺省的默认构造函数,就可以不写这行代码
	{}
private:
	int _year; // 声明
	const int _n;
	int& _ref;
	A _aa;
};
int main()
{
	Date d1(2022, 5, 20); // 对象定义
	system("pause");
	return 0;
}

如上述代码,我们没写, _aa(a)这一行,但我们提供了默认构造函数,结果表明依然可以初始化。

️️️️️️️️️️️️️️️️️️️️️️️️️️️️️️️️️:

下面我们再看一个例子:

class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		_top = 0;
		_capacity = capacity;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
public:
	MyQueue(int size = 100)
		:_size(size)//如果这里什么都没写,那么默认初始化列表就表示_st1就调用_st1的默认构造,_st2同理,
		//_size如果给了缺省值,就用缺省值初始化,没给就是随机值,
		//如果显式(int size = 1)、_size(size)写了  就用显式的这个值初始化
	{}
private:
	Stack _st1;
	Stack _st2;
	size_t _size = 1000; // 缺省值  如果上面哪个地方给了缺省参数,这里的这个缺省值也没用了
};
int main()
{
	MyQueue mq;
	return 0;
}

代码解释:在MyQueue类中声明_size的时候给了一个缺省值,然后在默认构造函数的地方也给了缺省形参,还在初始化列表中对_size进行初始化。如下结果:

class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		_top = 0;
		_capacity = capacity;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
public:
	MyQueue(int size = 100)
		//:_size(size)//如果这里什么都没写,那么默认初始化列表就表示_st1就调用_st1的默认构造,_st2同理,
		//_size如果给了缺省值,就用缺省值初始化,没给就是随机值,
		//如果显式(int size = 1)、_size(size)写了  就用显式的这个值初始化
	{}
private:
	Stack _st1;
	Stack _st2;
	size_t _size = 1000; // 缺省值  如果上面哪个地方给了缺省参数,这里的这个缺省值也没用了
};
int main()
{
	MyQueue mq;
	return 0;
}

如果上述_size没有在初始化列表初始化,那么_size就被声明时候给的缺省值初始化。如下结果:

我们再看三段代码,看看他们的不同之处:

class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		_top = 0;
		_capacity = capacity;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
public:
	MyQueue(int size = 100)
		:_size(size)
	{}
private:
	Stack _st1;
	Stack _st2;
	size_t _size = 1000;
};
int main()
{
	MyQueue mq(10);
	return 0;
}
class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		_top = 0;
		_capacity = capacity;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
public:
	MyQueue(int size)
		:_size(size)
	{}
private:
	Stack _st1;
	Stack _st2;
	size_t _size = 1000;
};
int main()
{
	MyQueue mq(10);
	return 0;
}
class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		_top = 0;
		_capacity = capacity;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
class MyQueue
{
public:
	MyQueue(int size = 100)
	{}
private:
	Stack _st1;
	Stack _st2;
	size_t _size = 1000;
};
int main()
{
	MyQueue mq(10);
	return 0;
}

explicit关键字

构造函数不仅可以构造和初始化对象,对于单个参数的构造函数,还具有类型转换的作用。

下面我们还是看一段代码:

class Date
{
public:
	/*explicit Date(int year)
	:_year(year)
	{
	cout << "Date(int year)" << endl;
	}*/
	Date(int year)
		:_year(year)
	{
		cout << "Date(int year)" << endl;
	}
private:
	int _year;
};
int main()
{
	Date d2 = 2022; // 构造 + 拷贝构造 -》 优化 合二为一
	system("pause");
	return 0;
}

代码解释:当没有在有参构造前面加explicit的时候,程序不会报错,以Date d2 = 2022这种方式来调用构造函数,其实是先调用有参构造,在调用拷贝构造函数完成!

️如果我们加上explicit关键字:

class Date
{
public:
	explicit Date(int year)
	:_year(year)
	{
	cout << "Date(int year)" << endl;
	}
private:
	int _year;
};
int main()
{
	//Date d1(2022); // 构造
	Date d2 = 2022; // 构造 + 拷贝构造 -》 优化 合二为一
	//Date& d6 = 2022;//一开始就说了对常数取别名要加const
	//const Date& d6 = 2022;//整型2022被不同类型区别名时,前面就说了,临时变量具有常性,此时是引用的2022的临时变量的别名
	system("pause");
	return 0;
}

程序报错:

这是因为这其中发生了隐式类型转换,当加上explicit时,就阻止了这个转换!

️再比如说:

class Date
{
public:
	explicit Date(int year)
	:_year(year)
	{
	cout << "Date(int year)" << endl;
	}
private:
	int _year;
};
int main()
{
	const Date& d6 = 2022;//整型2022被不同类型区别名时,前面就说了,临时变量具有常性,此时是引用的2022的临时变量的别名
	system("pause");
	return 0;
}

我们引用类型和引用实体不是同一个类型的时候,我们需要加上const,这是在前文就说过(前文查看),这其中发生隐式类型转换的时候产生了临时变量,需要加上const,那么这个时候加上explicit就阻止了这个转换,所以报错!

️总结:反正隐式转换法中会有类型的转换,explicit可以阻止这种转换!

到此这篇关于C++类与对象深入之运算符重载与const及初始化列表详解的文章就介绍到这了,更多相关C++类与对象内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++浅析类与对象基础点

    目录 认识类和对象 访问限定符 this指针 认识类和对象 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题. C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成 举一个例子,如果我们要设计一个点餐平台,依照生活中的例子 那么C:商家上架商品,客户点餐,通知商家制作外卖,通知骑手配送,客户吃完点评.....(过程) 而C++:商家.客户.骑手(对象) 从这个地方就衍生出了”类”这个概念. 我们在学习C语言的时候有过创建结构体 s

  • C++类与对象深入之静态成员与友元及内部类详解

    目录 一:静态成员 1.1:静态成员分类 1.2:静态成员变量 1.3:静态成员函数 1.4:总结特性 1.5:试题示例 1.6:C++11成员初始化新玩法 二:友元 2.1:全局函数做友元 2.2:类做友元 2.3:成员函数做友元 三:内部类 3.1:概念 3.2:特性 一:静态成员 静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员.C++里面尽量用静态成员变量代替全局变量. 1.1:静态成员分类 1️静态成员变量: 所有对象共享同一份数据 在编译阶段分配内存 类内声明,

  • C++浅析类与对象的基础

    目录 面向过程和面向对象 类的引入 访问限定符 封装 类的作用域 类的实例化 面向过程和面向对象 类和对象是 C++ 的核心特性 我们之前的C语言就属于面向过程,关注过程,分析求解问题的步骤再通过函数调用解决问题:而现在C++是基于面向对象,关注对象,将一个问题拆分成不同对象,依靠对象之间的交互完成. 比如有一个图书馆系统,用C语言面向过程思路就是:统计图书,图书分类,同步上架图书数据,记录借阅信息.而面向对象我们会创建两个类,图书馆和用户,我们关心的是图书馆和用户之间的关系,再分别实现交互,这

  • C++全面精通类与对象

    目录 运算符重载 运算符复用 前置后置运算符 const C++ 的IO流 初始化列表 explicit 关键字 运算符重载 C++语法设计很巧妙,比如运算符重载一个 > bool operator>(const Date& d) { return !(*this <= d); } 这里可以结合前面的内联函数来进一步提高代码的效率,而内联函数不支持 .h 和 .cpp 分开写,所以成员函数要成为内联函数最好的办法就是把定义放在类里面,类里面定义的会被默认为是 inline 内联函

  • C++深入刨析类与对象的使用

    目录 this指针 this指针存放在哪 nullptr与类 类的默认成员函数 构造函数 意义 析构函数 拷贝构造 运算符重载 this指针 现在给出一段代码,实现一个普通的日期 date 的打印: class date { public: void print() { cout << year<<' ' << month <<' '<< day << endl; } void init(int y, int m, int d) {

  • C++简单又轻松的讲解类和对象中友元函数

    目录 友元 浅解概念 友元目的 友元的三种实现 全局函数做友元 类做友元 成员函数做友元 注意事项 总结 友元 用到关键字 friend 浅解概念 举一个非常实际的例子,假如端午节到了你煮了两种粽子,一种是普通的糯米粽子,一种是特殊的五花肉粽子,糯米粽只要是客人都可以品尝,而五花肉棕只限好朋友品尝,这时候就可以用到友元的知识了.在程序里,有些私有属性也想让类外特殊的一些函数或者类访问,就要用到友元函数. 友元目的 让一个函数或者类,访问另一个类的私有属性 友元的三种实现 全局函数.成员函数.类都

  • C++类与对象深入之引用与内联函数与auto关键字及for循环详解

    目录 一:引用 1.1:概念 1.2:引用特性 1.3:常引用 1.4:使用场景 1.5:引用和指针的区别 二:内联函数 2.1:概念 2.2:特性 2.3:面试题 三:auto关键字 3.1:auto简介 3.2:auto使用细则 3.3:auto不能推导的场景 四:基于范围的for循环 4.1:范围for循环的语法 4.2:范围for循环的使用条件 一:引用 1.1:概念 引用不是定义一个新的变量,而是给已经存在的变量取一个别名.注意:编译器不会给引用变量开辟内存空间,他和他的引用变量共用同

  • C++类与对象深入之构造函数与析构函数详解

    目录 对象的初始化和清理 一:构造函数 1.1:构造函数的特性 1.2:构造函数的分类 二:析构函数 2.1:概念 2.2:特性 三:拷贝构造函数 3.1:概念 3.2:特性 3.3:拷贝构造函数调用时机 3.4:构造函数调用规则 对象的初始化和清理 生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全.C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置. 一:构造函数 对象的初始化和清理也是两个非常重要的安全问题,一个

  • C++类与对象深入之运算符重载与const及初始化列表详解

    目录 一:运算符重载 相等运算符重载 赋值运算符重载 小于运算符重载 二:const成员 const修饰类的成员函数 三:cin.cout重载 四:初始化列表 构造函数赋初值 初始化列表 explicit关键字 一:运算符重载 C++为了增强代码的可读性引入了运算符的重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型以及参数列表,其返回值类型与参数列表与普通函数类似. 函数名字为:关键字operator后面接需要重载的运算符符号 函数原型:返回值类型 operator操作符(参数列表)

  • C++运算符重载 成员函数与友元函数详解

    复制代码 代码如下: #include<iostream>using namespace std;class A{    int x,y;    public:    A(int xx,int yy):x(xx),y(yy){}    A(){x=0;y=0;}    A operator+(const A&b) //不加const限定,也可以    { return A(x+b.x,y+b.y); }    A operator-()    { return A(-x,-y); } 

  • C++之重载 重定义与重写用法详解

    一.重载(重载函数) 重载函数是C++为了方便使用,允许在同一范围中(一个类中)声明几个功能类似的同名函数,但是这些同名函数的形参(指参数的个数.类型或者顺序至少有一个)必须不同 1.代码实现在一个类中fun()函数的重载: #include<iostream> using namespace std; class Base { public: void fun() { cout << "Base::fun()" << endl; } void fu

  • PHP的重载使用魔术方法代码实例详解

    摘录PHP官网对PHP重载的解释: PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法.我们是通过魔术方法(magic methods)来实现的. 当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用.本节后面将使用"不可访问属性(inaccessible properties)"和"不可访问方法(inaccessible methods)"来称呼这些未定义或不可见的类属性或方法. 所有

  • 基于Java class对象说明、Java 静态变量声明和赋值说明(详解)

    先看下JDK中的说明: java.lang.Object java.lang.Class<T> Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class tha

  • 判断python对象是否可调用的三种方式及其区别详解

    查找资料,基本上判断python对象是否为可调用的函数,有三种方法 使用内置的callable函数 callable(func) 用于检查对象是否可调用,返回True也可能调用失败,但是返回False一定不可调用. 官方文档:https://docs.python.org/3/library/functions.html?highlight=callable#callable 判断对象类型是否是FunctionType type(func) is FunctionType # 或者 isinst

  • Mapstruct对象插入数据库某个字段总是为空的bug详解

    目录 前言 如何调试Maven插件 源码解析 前言 在一次需求的开发过程中,发现一个对象插入数据库时某个字段总是为空. 版本:lombok:1.18.24.mapstruct:1.5.2.Final 简化后的代码如下: @Autowired private PersonService personService; public void test1(){ Person person = personService.findById(1L); PersonDto personDto = Perso

  • IOS 开发之对象为空的判断(nil、null)详解

    IOS 开发之对象为空的判断(nil.null)详解 前言: 在开发中,会遇到很多空的情况,有时候取得对象(null),还有时候会得到<null>的情况,我们需要判断是否为空,进行return: id result; // 针对(null)这种情况 if(result == nil) return; // 针对<null>的情况 if([result isEqual:[NSNull null]]) return; 前者的判断,我们用的比较频繁,但后者,用的比较少,一般赋值给nil之

  • Java 反射修改类的常量值、静态变量值、属性值实例详解

    前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值. 定义一个实体类 class Bean{ private static final Integer INT_VALUE = 100; } 利用反射修改私有静态常量方法 System.out.println(Bean.INT_VALUE); Field field = Bean.class.getField("INT_VALUE

  • java对象初始化代码详解

    本文主要记录JAVA中对象的初始化过程,包括实例变量的初始化和类变量的初始化以及final关键字对初始化的影响.另外,还讨论了由于继承原因,探讨了引用变量的编译时类型和运行时类型 一,实例变量的初始化 这里首先介绍下创建对象的过程: 类型为Dog的一个对象首次创建时,或者Dog类的static字段或static方法首次访问时,Java解释器必须找到Dog.class(在事先设定好的路径里面搜索):  找到Dog.class后(它会创建一个Class对象),它的所有static初始化模块都会运行.

随机推荐