学习《c++ primer》第13章复制控制时,遇到一个很纠结的问题。。。

infinity17 2011-01-17 12:12:08
代码如下:

#include <iostream>
using namespace std;

class A
{
public:
A()
{
cout<<"A::A()"<<endl;
}

private:
//复制构造函数,声明为私有!
A(const A& a)
{
cout<<"A::A(const A&)"<<endl;
}
};
int main(int argc, char* argv[])
{
//复制初始化,用一个临时对象初始化a。但由于复制构造函数是私有的,编译失败
A a=A();

//诡异的情况发生了。直接初始化,用一个临时对象直接初始化a
//应该会调用复制构造函数,但A(const A& a)是私有的,所以编译会失败。但编译通过了!?但没有任何输出。。。。。
A a(A());



cin.get();
return 0;
}

请教一下各位大侠,如上所见,这是什么情况啊。我彻底晕了,A a(A());这句到底发生了什么?
...全文
244 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
crafet 2011-01-17
  • 打赏
  • 举报
回复
真是有意思
effictive系列写的真好,读起来也舒服,还会让你找个板凳先坐下来,
呵呵,反观国内,额
itslmde 2011-01-17
  • 打赏
  • 举报
回复
itslmde 2011-01-17
  • 打赏
  • 举报
回复
噢,不是BJ,是BS,原谅我的简写!
itslmde 2011-01-17
  • 打赏
  • 举报
回复
算是见识了,C++里的一条通用规则——几乎任何东西都可能被分析成函数声明
这就是灵活性带来的代价?果然是复杂的东西,当年BJ怎么能把C改成了这样,唔,我还是用C+Python吧。
zjs100901 2011-01-17
  • 打赏
  • 举报
回复
重新排下版。

我们会从最基本的开始。这行声明了一个函数f带有一个double而且返回一个int:

int f(double d);

第二行作了同样的事情。名为d的参数左右的括号是多余的,被忽略:

int f(double (d)); // 同上;d左右的括号被忽略

下面这行声明了同样的函数。它只是省略了参数名:

int f(double); // 同上;参数名被省略

你应该很熟悉这三种声明形式了吧,虽然可以把括号放在参数名左右这一点可能比较新。(在不久以前我也觉得它新。)

现在让我们再看看三个函数声明。第一个声明了一个函数g,它带有一个参数,那个参数是指向一个没有参数、返回double的函数的指针:

int g(double (*pf)()); // g带有一个指向函数的指针作为参数

这是完成同一件事的另一种方式。唯一的不同是pf使用非指针语法来声明(一个在C和C++中都有效的语法):

int g(double pf()); // 同上;pf其实是一个指针

照常,参数名可以省略,所以这是g的第三种声明,去掉了pf这个名字:

int g(double ()); // 同上;参数名省略

注意参数名左右的括号(就像f的第二种声明中的d)和单独的括号(正如本例)之间的区别。参数名左右的括号被忽略,但单独的括号指出存在一个参数列表:它们声明了存在指向函数的指针的参数。

用这些f和g的声明做了热身,我们准备检查本条款开头的代码。这里再写一遍:

list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());

打起精神,这声明了一个函数data,它的返回类型是list<int>。这个函数data带有两个参数:

第一个参数叫做dataFile。它的类型是istream_iterator<int>。dataFile左右的括号是多余的而且被忽略。
第二个参数没有名字。它的类型是指向一个没有参数而且返回istream_iterator<int>的函数的指针。
奇怪吗?但这符合C++里的一条通用规则——几乎任何东西都可能被分析成函数声明。如果你用C++编程有一段时间了,你应该会遇到另一个这条规则的表象。有多少次你会看见这个错误?

class Widget {...}; // 假设Widget有默认构造函数
Widget w(); // 嗯哦……
这并没有声明一个叫做w的Widget,它声明了一个叫作w的没有参数且返回Widget的函数。学会识别这个失言(faux pas)是成为C++程序员的一个真正的通过仪式。
pengzhixi 2011-01-17
  • 打赏
  • 举报
回复
好了,zjs100901给出了答案了。可以结贴了
zjs100901 2011-01-17
  • 打赏
  • 举报
回复
我们会从最基本的开始。这行声明了一个函数f带有一个double而且返回一个int:

int f(double d); 第二行作了同样的事情。名为d的参数左右的括号是多余的,被忽略:

int f(double (d)); // 同上;d左右的括号被忽略下面这行声明了同样的函数。它只是省略了参数名:

int f(double); // 同上;参数名被省略你应该很熟悉这三种声明形式了吧,虽然可以把括号放在参数名左右这一点可能比较新。(在不久以前我也觉得它新。)

现在让我们再看看三个函数声明。第一个声明了一个函数g,它带有一个参数,那个参数是指向一个没有参数、返回double的函数的指针:

int g(double (*pf)()); // g带有一个指向函数的指针作为参数这是完成同一件事的另一种方式。唯一的不同是pf使用非指针语法来声明(一个在C和C++中都有效的语法):

int g(double pf()); // 同上;pf其实是一个指针照常,参数名可以省略,所以这是g的第三种声明,去掉了pf这个名字:

int g(double ()); // 同上;参数名省略注意参数名左右的括号(就像f的第二种声明中的d)和单独的括号(正如本例)之间的区别。参数名左右的括号被忽略,但单独的括号指出存在一个参数列表:它们声明了存在指向函数的指针的参数。

用这些f和g的声明做了热身,我们准备检查本条款开头的代码。这里再写一遍:

list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>()); 打起精神,这声明了一个函数data,它的返回类型是list<int>。这个函数data带有两个参数:

第一个参数叫做dataFile。它的类型是istream_iterator<int>。dataFile左右的括号是多余的而且被忽略。
第二个参数没有名字。它的类型是指向一个没有参数而且返回istream_iterator<int>的函数的指针。
奇怪吗?但这符合C++里的一条通用规则——几乎任何东西都可能被分析成函数声明。如果你用C++编程有一段时间了,你应该会遇到另一个这条规则的表象。有多少次你会看见这个错误?

class Widget {...}; // 假设Widget有默认构造函数
Widget w(); // 嗯哦……
这并没有声明一个叫做w的Widget,它声明了一个叫作w的没有参数且返回Widget的函数。学会识别这个失言(faux pas)是成为C++程序员的一个真正的通过仪式。
zjs100901 2011-01-17
  • 打赏
  • 举报
回复
《Effective STL》 当中也有类似一个例子:Item6:警惕C++最令人恼怒的解析

假设你有一个int的文件,你想要把那些int拷贝到一个list中。这看起来像是一个合理的方式:

ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), // 警告!这完成的并不
istream_iterator<int>()); // 是像你想象的那样这里的想法是传一对istream_iterator给list的区间构造函数(参见条款5),因此把int从文件拷贝到list中。

这段代码可以编译,但在运行时,它什么都没做。它不会从文件中读出任何数据。它甚至不会建立一个list。那是因为第二句并不声明list,而且它也不调用构造函数。其实它做的是……,它做得很奇怪。我不敢直接告诉你,因为你可能不相信我。取而代之的是,我得一点一点展开这个解释。你坐下了吗?如果没有,你可能要找找附近有没有椅子……
zjs100901 2011-01-17
  • 打赏
  • 举报
回复
A a(A());实际上是一个函数声明,只是一个函数声明而已。该函数的返回类型为A,函数的名字为a,函数的参数类型,是一个函数指针,到底是怎样的函数指针呢?
设有一个函数,名字叫做FunctionName,定义如下:
A FunctionName()
{
A aaa;
return aaa;
}
这个函数的指针,就可以作为刚才的a的参数,也就是说可以如下调用:
a( FunctionName );
#include<iostream>
using namespace std;

class A
{
public:
A()
{
cout<<"A::A()"<<endl;
}

A(const A& a)
{
cout<<"A::A(const A&)"<<endl;
}
};

A FunctionName()
{
A aaa;
return aaa;
}

A b(A())
{
A aaa;
return aaa;
}

int main(int argc, char* argv[])
{
A b(A());
b( FunctionName );
cin.get();
return 0;
}
tisyang 2011-01-17
  • 打赏
  • 举报
回复
看起来像是得到一个 A 的对象,但是事实上你不能用这个 “对象” 做任何事情
我给这个类加一个成员用来打印字符串,然后用 a.printA() 调用,结果是编译不通过
error: request for member 'printA' in 'a', which is of non-class type 'A(A (*)())'
编译器是 MinGW。

65,206

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧