为什么(cin>>str)可以做条件判断,explicit

本文围绕C++展开,介绍了关键字explicit的作用,它用于修饰类的构造函数,防止隐式类型转换,可用于单参数或除首参数外其余有默认值的多参数构造函数。还解释了为什么(cin>>str)能做判断条件,是因运算符重载返回istream对象,其调用重载函数返回bool或void *。

explicit作用及其介绍

1.c++中的关键字explicit主要是用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。构造函数默认情况声明为implicit。单参数的构造函数默认可以构成隐式类型转换,eg:当编译器试图编译某一条语句时,如果某一函数的参数类型不匹配,编译器就会尝试进行隐式转换,如果隐式转换后能正确编译,编译器就会继续执行编译过程,否则报错。
eg:

class A
{
public:
	//explicit  A(int a = 0)A a = (A)2;
		  A(int a = 0)//A a = 2;
		:_a(a)
	{}

类A是单参数的构造函数,如果不加explicit,那么可以支持A a =2 反之则不支持,如果加了explicit,此时只能像上述代码写的那样进行显示的类型转换:A a = (A)a,个人理解:此时单参数先自身构造出一个类对象(这个类对象是一个临时变量),然后这个临时的类对象再拷贝赋值给 a,由于编译器的优化,两个步骤变成一步,直接就是隐式类型转换。
2.explicit只能用于类内部的构造函数声明上,而不能用在类外部的函数定义上,其也可以作用于多参数的构造函数,但此时要求构造函数从第二个参数开始都有默认值
总结: 当我们不希望自动类型转换时用explicit,对于仅有一个参数或除第一个参数外其余参数均有默认值的构造函数,尽可能使用explicit修饰
如果类的构造函数声明和定义分别在两个文件中时,explicit只能写在构造函数的声明中,不能写在定义中

为什么(cin>>str)可以做判断条件

通过上述可以了解到,是否加explicit决定了是否可以从内置类型隐式类型转换成自定义类型
而有一个运算符重载比较特殊,其支持将自定义类型转换成内置类型

class A
{
public:
	//explicit  A(int a = 0)A a = (A)2;
		  A(int a = 0)//A a = 2;
		:_a(a)
	{}
	operator bool()
	{
		if (_a < 10)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	operator int()
	{
		if (_a < 10)
		{
			return 2;
		}
		else
		{
			return -1;
		}
	}
	
private:
	int _a;
};
int main()
{
	A a = 2;
	bool ret = a;
	int t = a;

	return 0;
}

结果是:ret = true,t = 2;
C++对类似于上述的函数

operator bool()
operator int()

做了特殊处理,不用返回值。
此时并不是自定义类型直接转化成内置类型,而是转化成调用operator bool()与operator int ()的重载函数,调用函数之后返回值产生的一个临时变量然后再赋值给y,而这个临时变量我们是可以自己定义的,以为函数的逻辑是我们定义的。
所以 为什么 (cin>>str 可以做判断的条件呢?)

class A
{
public:
	//explicit  A(int a = 0)A a = (A)2;
		  A(int a = 0)//A a = 2;
		:_a(a)
	{}
	operator bool()
	{
		if (_a < 10)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	void Print()
	{
		cout << _a << endl;
	}
	void Set(int a)
	{
		_a = a;
	}
private:
	int _a;
};
int main()
{
	A a = 2;
	A a = (A)2;
	int x;
	bool ret = a;
	while (a)
	{
		a.Print();
		cin >> x;
		a.Set(x);
	}
	return 0;
}


在这里插入图片描述
通过cpp官方网站源码可以看出,此时运算符重载返回的是一个istream的对象,而istream对象重载了一个非常特殊的运算符
在这里插入图片描述
在这里插入图片描述
所以上述代码中的
cin>>str 相当于转换成 cin. operator bool() c++11
或 operator void *() c++98;

所以**while (cin>>str)**中的cin>>str
其返回值是istream,而此时istream对象又去调用重载函数,返回值是bool或者void *也就自然可以充当条件。
好比上述代码中的

while (a)
	{
		a.Print();
		cin >> x;
		a.Set(x);
	}

其中的while(a)相当于是while(a.operator bool())
调用函数后,根据函数定义来确定返回值是true还是false。
可以看到源码中的istream的重载 加了explicit 指的是不支持 类似于这样写A a = 2;int b = a;;加了explicit后此时不会调用这个重载函数,但如果是条件编译的 while(a) 此时还是依然会调用重载函数,根据重载函数的返回值做判断。
这本身就是一个自洽的说法,但没办法,我们只是学习者,当作特例记住

无论是

A a = 2;int b = a;还是while(a),都是调用了重载函数,根据函数的返回值,产生的临时变量赋值或是用返回值当作条件编译。


#include <iostream> #include <vector> #include <string> #include <sstream> #include <cstdlib> using namespace std; struct TypeNode { string type_name; TypeNode* first = NULL; TypeNode* second = NULL; TypeNode(string t) : type_name(t), first(NULL), second(NULL) {} }; vector<TypeNode*> vars; vector<string> var_names; void addVariable(const string& name, const string& type_str) { if (type_str == “int” || type_str == “double”) { vars.push_back(new TypeNode(type_str)); } else { size_t pos = type_str.find(“<”); string base_type = type_str.substr(0, pos); if (base_type != "pair") { cerr << "Error: Invalid type definition!" << endl; exit(-1); } string inner_types = type_str.substr(pos + 1, type_str.size() - pos - 2); stringstream ss(inner_types); string left_type, right_type; getline(ss, left_type, ','); getline(ss, right_type); TypeNode* node = new TypeNode("pair"); node->first = new TypeNode(left_type); node->second = new TypeNode(right_type); vars.push_back(node); } var_names.push_back(name); } TypeNode* getTypeNodeByName(const string& name) { for (size_t i = 0; i < var_names.size(); ++i) { if (var_names[i] == name) return vars[i]; } return NULL; } string queryType(TypeNode* root, const vector<string>& steps) { if (!root) return “”; if (steps.empty()) return root->type_name; string step = steps.front(); if (step == "first" && root->first) { return queryType(root->first, vector<string>(steps.begin() + 1, steps.end())); } else if (step == "second" && root->second) { return queryType(root->second, vector<string>(steps.begin() + 1, steps.end())); } else { return ""; } } string resolveQuery(const string& query_str) { size_t dot_pos = query_str.find(‘.’); string var_name = query_str.substr(0, dot_pos); string rest = query_str.substr(dot_pos + 1); TypeNode* root = getTypeNodeByName(var_name); if (!root) return ""; vector<string> steps; while (!rest.empty()) { size_t next_dot = rest.find('.'); string current_step = rest.substr(0, next_dot); steps.push_back(current_step); if (next_dot == string::npos) break; rest = rest.substr(next_dot + 1); } return queryType(root, steps); } int main() { int n, q; cin >> n >> q; cin.ignore(); for (int i = 0; i < n; ++i) { string line; getline(cin, line); size_t space_pos = line.find(’ '); string type_def = line.substr(0, space_pos); string var_name = line.substr(space_pos + 1); if (!var_name.empty() && var_name[var_name.size()-1] == ‘;’) { var_name.erase(var_name.size()-1); } addVariable(var_name, type_def); } for (int i = 0; i < q; ++i) { string query; cin >> query; cout << resolveQuery(query) << endl; } return 0; }样例输入 #1 5 5 int a1; double a2; pair<int,int> pr; pair<pair<int,int>,pair<int,int>> BBKKBKK; pair<int,pair<pair<double,int>,double>> __frost_ice; a1 a2 pr.first BBKKBKK __frost_ice.second.first.second 错误输出: int 期望输出: int double int pair<pair<int,int>,pair<int,int>> int 给出上述代码改正后
03-31
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天少点debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值