您的位置:首页 > 编程语言 > C语言/C++

c++中比较容易有歧义的语法

2017-10-22 12:20 225 查看
无法确定是调用类构造函数还是一个函数指针指向类的类型

代码如下:

class Monkey{
public:
Monkey(){
std::cout<<"Monkey constructor has been used"<<std::endl;
}
};

void testIfMethodOrConstructor(){
Monkey m1();//有歧义
}


这样的话testIfMethodOrConstructor函数可理解为声明一个无且返回值为Monkey的函数指针,也可理解为声明一个Moneky类型的对象,使用类的无参构造函数对其进行初始化。

这里编译器的实际情况是默认为了指针,所以可能与我们想要的结果不太一样,于是当test函数被调用的时候不会打印出语句。

修改方法可以为

- 去掉m1后面的括号,这样就不会认为是函数的可能,只能是一个类变量的声明

- 亦或者是调用initializer_list初始化,消除歧义

#include <initializer_list>
...
void testIfMethodOrConstructor(){
// Monkey m1();
Monkey m2;
Monkey m3{};//注意这里是中括号
}


这里的initializer_list初始化,在实际中就是{}进行赋值初始化,这种用法在string中也有string s={‘a’,’b’};string实际是char数组组成的。

所以修改后的上面test函数被调用后会输出两条打印语句

在上面基础上更一步,上面的test函数两种改进后的做法是显示的调用了Monkey的无参构造函数,这里我们将Monkey的构造函数修改如下:

explicit Monkey(int i){
std::cout<<"Monkey constructor has been explicit used"<<std::endl;
}


将其变为带参数的explicit函数,类中没有无参构造函数,所以testIfMethodOrConstructor中的情况为

void testIfMethodOrConstructor(){
// Monkey m1();
Monkey m2;   //错误,没有无参构造函数
Monkey m3{}; //错误,没有无参构造函数
Monkey m4=1;//注意,无法隐式转换
Monkey m5{1};//正确
Monkey m6(1);//正确
}


explicit的区别于此,言归正传,这里在Monkey修改后的情况下,增加一个Tiger类,如下:

class Tiger{
public:
explicit Tiger(Monkey m){
cout<<"Tiger constructor has been explicit used"<<endl;
}
};

void testTiger(){
int i=3;
Tiger tt(Monkey(i)); //调用有歧义
cout<<"end of testTiger"<<endl;
}


testTiger()函数被调用后无法输出Tiger的显示构造函数,说明这里的调用有歧义。这里之所以有歧义的地方在Tiger tt(Monkey(i))不会被理解为一个带初始参数的Tiger对象,而被曲解为函数声明Tiger tt(Monkey i),一个Monkey参数的返回值为Tiger的函数,i包围的括号变成了冗余。这与上面的歧义相似,因此不会有任何构造函数语句输出。

修改方法,

Tiger构造函数外面再加一层括号()

Tiger构造函数的括号()改为中括号,也就是initializer_list初始化的形式

void testTiger(){
int i=3;
Tiger tt(Monkey(i)); //函数声明
Tiger tt1((Monkey(i)));  //修改方法一
Tiger tt2{(Monkey(i))}; //修改方法二
cout<<"end of testTiger"<<endl;
}


输出语句为

Monkey constructor has been explicit used
Tiger constructor has been explicit used
Monkey constructor has been explicit used
Tiger constructor has been explicit used
end of testTiger


总结:之所以造成歧义,个人发现最大的原因在于小括号()造成的函数声明与类的默认构造函数的不明确,感觉最好用的做法就是初始化用{},当然这得c++11的支持特性
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: