VS上写的C++程序,为什么在构造函数中的参数总表中,给一个字符数组形参初始化用来存放字符串,编译会显示默认实参和形参不匹配?
1.问题描述:
在student类中构造函数中,给形参字符数组初始化:char sname[]="no name"编译会报错,错误信息为:error C2440: “默认参数”: 无法从“const char [8]”转换为“char []”
在用定义好的类实例化对象时,传入参数处也会报错:student("朱明",86302535); ,错误信息为:error C2440: “<function-style-cast>”: 无法从“initializer list”转换为“student”
2.程序总代码如下
#include<iostream>
#include<cstring>
#pragma warning(disable:4996) //避免使用strcpy 报错
using namespace std;
class studentID {
long value; //数据成员
public:
studentID(long id = 0) { //函数名与类名相同,为构造函数,类中定义构造函数,id为成员函数的形参
value = id; //正常的参数传递
cout << "赋给学生学号为:" << value << endl;
}
~studentID() { //析构函数
cout << "删除学号:" << value;
}
};
class student {
private:
studentID id; //成员对象
char name[20]; //未解决出错系列,实参行参为字符串传递问题
public:
student(char sname[]="no name", long sid = 0) :id(sid) { //含析构函数的成员对象
cout << "学生姓名:" << sname << endl;
strcpy(name,sname);
//name = sname;
}
~student() {
cout << "删除学生姓名:" << name << endl;
}
};
int main() {
student("朱明",86302535); //类student的一个实例化对象
system("pause");
return 0;
}
总程序图片:
编译出错信息:
补充说明:程序原来的目的是想传入一个人名,所以用一个数组来做形参,初始化值为字符串"no name",但出现了上述错误;我试过,如果简单修改下程序,传入的是单个字符的话,则程序正常。比如构造函数初始化的地方做如下修改:char sname='a' ,当然前面数据成员也要修改为char name,其它地方也做相应修改:strcpy(name,sname)改为name = sname,实例化的地方student("朱明",86302535)改为student('x',86302535) ,则程序正常
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
c++版藥丸...一天都沒人回答...果然沒什麼人留下來了...回答的答案也沒有人搭理...
它已經提示你了嘛, 你的字符串
"朱明"
的類型是const char*
, 至於爲什麼是這個類型呢?因爲c++的string literal("朱明")是不可修改, 從c++11開始就只能用以下兩種方法聲明了:
const char* str = "朱明";
const str
指向具體實現中的text segment,const
保護了此數據`or
str[] = "朱明";
str
本身也會深複製"朱明"到Activation Records, 其具體實現可以是stack`這兩者的目的都是爲了保證text segment中的數據不被修改. 原因窩在註釋中解釋了.
如果你的形參(parameter)是
char *
, 那麼傳進來的參數不就有了被修改text segment(這裏是string literal)"朱明"
)的危險, 所以爲了安全期間, c++11開始ban了這樣的方式,當然, 你可能會有這樣的亦或:
其實呢, 這該c背鍋, c風格的字符串在c++裏面不是一等公民, 或者說first-class, (這裏有人會誤解或者說是因爲字符串或者函數他們不是base type, 而是derived type, 所以不能做到傳值, 不, 不是這樣的, struct同樣是derived type, 它就能傳值, derived type僅僅是composite type的alias, 和first-class是無關的.
換而言之, 它不能作爲參數傳遞, 再換而言之, 它不能在傳參時進行深拷貝, 它能做的只是傳指針, 同樣的道理, 如果你想將函數傳遞, 在c語法裏面也只能傳函數指針, c++11開始能用struct來模擬lambda實現真正傳遞函數的功能.
好, 饒了一圈, 回答剛剛那個問題, 現在你應該明白了, 你這裏的形參
char[]
不得不退化成char*
了, 其實vs的提示也暗示你這個信息了. 你的解決辦法有這麼幾種:std::string
/std::wstring
const char*
/char const *
其實很早以前人們就發現text segment在這種情況下被修改會很危險, 但是c這貨一直不高興寫進標準來規定, 不過posix倒是弄了個
strdup(3)
, 然後c才也跟着糊了個出來, 貌似posix不嚴格要求帶error code
, 後來把may
改成shall
了. 那麼cppreference的表述就出錯了...或許窩該去改下cppreference...更新: 改好了...所以跟我大聲唱:
Pointer is shit, C is shit.
Update:
補充下標準中(n4741)的wording:
diff在這裏可以看到
http://www.open-std.org/jtc1/...
这个代码本身的编译执行是没有错误的, (在我这个默认的初始编译器环境下), 但是, 在你的环境下, 有错误, 可能是因为这个原因. C2440 can occur because of conformance changes to the compiler in Visual Studio 2015 Update 3.
根据这个错误描述文档, 我打开了
/Zc:strictStrings
这个编译器选项, 才会出现你所说的错误, 所以, 你那里应该是默认开启了那个选项, 根据上面的链接.你这个代码的问题就是类型转化的问题, 使用
char sname[]="no name"
, 如果程序在运行时, 修改了sname
字符数组的内容, 会出问题, 如果没有修改, 就不会有问题. 但是在写代码中, 这个是需要注意的.