一个奇怪的类初始化问题

prhanxben 2011-03-08 12:18:16
如下代码,编译报错。不知道为啥。

class C{
public:
C(){
cout<<"cccc"<<endl;

}
C(C& c){
m = c.m;
cout<<"copy constructor"<<endl;
}
string m;
};

int main() {
string x ="ssss";
C c2 = C(); //报错:no matching function for call to 'C::C(C)'
}

如果把C的拷贝构造函数删掉,就能正确运行。为啥? 编译器是G++

...全文
267 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
prhanxben 2011-03-13
  • 打赏
  • 举报
回复
感谢各位帮忙,小结一下:
1. 形如 C c1 = C(); 的语句,字面上看会调用默认构造函数和拷贝构造函数,但因为等号右边的是个临时对象,编译器会将其优化为“在拷贝的目标地址中直接构造临时对象”,即在c1的地址上调用C();
类似情况还有从函数返回值定义一个对象:
C test(){
C temp; //这个temp的地址与c1的地址是一样的。
return temp;
}
C c1 = test(); //也不会调用拷贝构造。

2. 运行期不会调用拷贝构造函数,但编译器一样会对拷贝构造进行语法验证,因为临时对象都是const,故拷贝构造函数原型 C(const C& c); 也需要声明const参数。
但经测试,g++编译器要求const声明,vc编译器则不需要。
ljsdaya 2011-03-10
  • 打赏
  • 举报
回复
8L说得对~
pcliuguangtao 2011-03-09
  • 打赏
  • 举报
回复
#include <iostream>
#include <string>
using namespace std;

class C{
public:
C(){
cout<<"cccc"<<endl;

}
C( C& c){
m = c.m;
cout<<"copy constructor"<<endl;
}
string m;
};

int main() {
string x ="ssss";
C c2=C(); //报错:no matching function for call to 'C::C(C)'
return 0;

}

LZ的问题有:
1、C c2=C() 为什么出错误?为什么构造函数要改成C(const C& c)?
2 、为什么调用无参构造函数时不能写成:C c(); ?

开始介绍关于类构造函数的知识点:
1、 首先,类的构造函数是用来处理对像的初始化的,并且,构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来(显式)的调用它,而是
在建立对象时自动执行。

那么怎样才叫显式的调用那?
比如已经有一个Student类
class Student
{
public:
Student(int num,int score ):
m_number( num ),m_score(score ){}
Studnet( ){} //默认构造函数
void PrintInfo( )
{
cout<<m_score<<" "<<m_number<<endl;

}
private:
int m_number;
int m_score;

};
Student stud_one.Student(123,96); //显式调用构造函数,编译器不允许
Student Stud_two(124,98); //正确的调用方式

Student stud_three;
stud_three.Student(125,99) ; //也是错误的,构造函数是在建立对象时有系统自动执行的,而且只执行一次。

2、默认构造函数:
建立一个对象时不需要给出实参的构造函数,叫该类的默认构造函数,又名缺省构造函数。
比如:
Student(){} // (如果我们没有自己定义一个默认构造函数,编译器默认添加该构造函数作为默认构造函数)、
Student(int num=123,int score=60):m_number(num),m_score(score){} //一个构造函数给出了所有数据成员的默认值

一个类只能有一个默认构造函数(也可以说成,可以不使用参数而调用的构造函数,一个类只能有一个),否则,系统就无法辨别出默认的时候应该调用那个来构造一个新的对象!

3、复制和赋值
复制:一个新的对象用一个已存在的对象来初始化,如 Student temp(stud_one); 或者 Student temp=stud_one;
但要注意,使用复制的前提是你已经定义了该类的复制构造函数 Student::Student(const Student& b )
(其中的const只是说明,在复制构造函数中不允许修改b对象的值!)
赋值:两个已存在的对象赋值,编译器已经给我们重载了“=”,所以我们不用自己再定义,比如 stud_one=stud_two;

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
下面来分析开始给出的两个问题:
1、C c2=C();
这个语句没有调用复制构造函数,而只是调用了C类的构造函数,所以会输出“cccc”,而不是“copy constructor”;
我们需要加上const,是因为G++是遵循了C++标准(2003)中的规定:非const引用不能绑定于临时对象(引用glues的~_~)。加上一个const才能编译通过。
2、C c()编译器理解为定义一个函数c(),他的返回值为一个C 类的对象像。
SINGLB 2011-03-09
  • 打赏
  • 举报
回复
学习 C++ 板块大牛好多啊
jial_on 2011-03-09
  • 打赏
  • 举报
回复
和编译器有关吧。
我在visual studio2010里面就能通过。
popo00fa 2011-03-09
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 prhanxben 的回复:]
果然是要加const,但语法上没区别啊,想不出为啥要这样。

另外请问为啥调用无参数构造函数的时候不能写括号,
C c1();
C c2 = C(c1); //这里报错no matching function for call to 'C::C(C (&)())'
难道g++会把 C c1(); 认成函数的声明?
[/Quote]
正解
dwtrace1 2011-03-09
  • 打赏
  • 举报
回复
楼主还很菜,要多多学习
stevenzhang1986 2011-03-09
  • 打赏
  • 举报
回复
C c2 = C();这句写的意思不明白
可以这样:
C c1;
C c2(c1); //调用复制构造函数
Cecho 2011-03-09
  • 打赏
  • 举报
回复
没有通过类的实例调用类里面的函数,除非它是静态函数
C c1;
C c2 = c1.C(); // 正确

////////////////////////////////////

C c = C.C(); //错误
um_java 2011-03-09
  • 打赏
  • 举报
回复
拷贝构造函数加上const
wbruce 2011-03-09
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 pengzhixi 的回复:]
http://topic.csdn.net/u/20110307/22/5fa8a45d-84ad-45ae-8caa-12c80ca6da3e.html
[/Quote]

学习了
Meteor_Code 2011-03-09
  • 打赏
  • 举报
回复
请重载等号,否则你就给出一个编译起默认的等号操作函数
GARY 2011-03-09
  • 打赏
  • 举报
回复
C(C& c)
{
m = c.m;
cout<<"copy constructor"<<endl;
}

C(c1);
按照c++标准,这里的调用会建立一个临时对象
临时对象都是const的,不能传递给非const引用形参
所以符合标准的复制否早函数参数应该是const引用类型吧。
yanran_hill 2011-03-09
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 prhanxben 的回复:]
C c1();
C c2 = C(c1); //这里报错no matching function for call to 'C::C(C (&)())'
难道g++会把 C c1(); 认成函数的声明?
[/Quote]
对,C++会认为c1是返回值为C的函数
yanran_hill 2011-03-09
  • 打赏
  • 举报
回复
[Quote=引用楼主 prhanxben 的回复:]
...
int main() {
string x ="ssss";
C c2 = C(); //报错:no matching function for call to 'C::C(C)'
}
[/Quote]
哈哈,看来是写C#或者java的代码太多了,所以可能不适应C++的语法了,俺现在也是迷恋C#,出手写的代码就会象这样:

public static int main()
{
string x ="ssss";
C c2 = new C();
}
pengzhixi 2011-03-08
  • 打赏
  • 举报
回复
额 你需要有一个C(const C&);这样的拷贝构造函数才可以优化掉这个临时对象。
prhanxben 2011-03-08
  • 打赏
  • 举报
回复
果然是要加const,但语法上没区别啊,想不出为啥要这样。

另外请问为啥调用无参数构造函数的时候不能写括号,
C c1();
C c2 = C(c1); //这里报错no matching function for call to 'C::C(C (&)())'
难道g++会把 C c1(); 认成函数的声明?
a369601152 2011-03-08
  • 打赏
  • 举报
回复
C c2 = C();
这句没看懂 你想干啥?
liutengfeigo 2011-03-08
  • 打赏
  • 举报
回复
C(const C& c)//这样才是标准的复制构造函数.
加载更多回复(4)

65,202

社区成员

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

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