鍍金池/ 問答/C++  HTML/ VS上寫的C++程序,為什么在構(gòu)造函數(shù)中的參數(shù)總表中,給一個字符數(shù)組形參初始化用

VS上寫的C++程序,為什么在構(gòu)造函數(shù)中的參數(shù)總表中,給一個字符數(shù)組形參初始化用來存放字符串,編譯會顯示默認實參和形參不匹配?

1.問題描述:
在student類中構(gòu)造函數(shù)中,給形參字符數(shù)組初始化:char sname[]="no name"編譯會報錯,錯誤信息為:error C2440: “默認參數(shù)”: 無法從“const char [8]”轉(zhuǎn)換為“char []”
在用定義好的類實例化對象時,傳入?yún)?shù)處也會報錯:student("朱明",86302535); ,錯誤信息為:error C2440: “<function-style-cast>”: 無法從“initializer list”轉(zhuǎn)換為“student”
2.程序總代碼如下

#include<iostream>
#include<cstring>
#pragma warning(disable:4996) //避免使用strcpy 報錯
using namespace std;
class studentID {
    long value; //數(shù)據(jù)成員
public:
    studentID(long id = 0) { //函數(shù)名與類名相同,為構(gòu)造函數(shù),類中定義構(gòu)造函數(shù),id為成員函數(shù)的形參
        value = id;   //正常的參數(shù)傳遞
        cout << "賦給學(xué)生學(xué)號為:" << value << endl;
    }
    ~studentID() {  //析構(gòu)函數(shù)
        cout << "刪除學(xué)號:" << value;
    }
};
class student {
private:
    studentID id; //成員對象
    char name[20]; //未解決出錯系列,實參行參為字符串傳遞問題
public:
    student(char sname[]="no name", long sid = 0) :id(sid) { //含析構(gòu)函數(shù)的成員對象                                            
        cout << "學(xué)生姓名:" << sname << endl;
        strcpy(name,sname);
        //name = sname;
    }
    ~student() {
        cout << "刪除學(xué)生姓名:" << name << endl;
    }
};
int main() {
    student("朱明",86302535); //類student的一個實例化對象
    system("pause");
    return 0;
}

總程序圖片:
圖片描述

編譯出錯信息:
圖片描述

補充說明:程序原來的目的是想傳入一個人名,所以用一個數(shù)組來做形參,初始化值為字符串"no name",但出現(xiàn)了上述錯誤;我試過,如果簡單修改下程序,傳入的是單個字符的話,則程序正常。比如構(gòu)造函數(shù)初始化的地方做如下修改:char sname='a' ,當(dāng)然前面數(shù)據(jù)成員也要修改為char name,其它地方也做相應(yīng)修改:strcpy(name,sname)改為name = sname,實例化的地方student("朱明",86302535)改為student('x',86302535) ,則程序正常

回答
編輯回答
撿肥皂

c++版藥丸...一天都沒人回答...果然沒什麼人留下來了...回答的答案也沒有人搭理...

它已經(jīng)提示你了嘛, 你的字符串"朱明"的類型是const char*, 至於爲(wèi)什麼是這個類型呢?

因爲(wèi)c++的string literal("朱明")是不可修改, 從c++11開始就只能用以下兩種方法聲明了:

  • const char* str = "朱明";
  • const str指向具體實現(xiàn)中的text segment, const保護了此數(shù)據(jù)`

or

這兩者的目的都是爲(wèi)了保證text segment中的數(shù)據(jù)不被修改. 原因窩在註釋中解釋了.

如果你的形參(parameter)是char *, 那麼傳進來的參數(shù)不就有了被修改text segment(這裏是string literal)"朱明")的危險, 所以爲(wèi)了安全期間, c++11開始ban了這樣的方式,

當(dāng)然, 你可能會有這樣的亦或:

窩明明形參(parameter)的類型是char[]不是char*呀.

其實呢, 這該c背鍋, c風(fēng)格的字符串在c++裏面不是一等公民, 或者說first-class, (這裏有人會誤解或者說是因爲(wèi)字符串或者函數(shù)他們不是base type, 而是derived type, 所以不能做到傳值, 不, 不是這樣的, struct同樣是derived type, 它就能傳值, derived type僅僅是composite typealias, 和first-class是無關(guān)的.

換而言之, 它不能作爲(wèi)參數(shù)傳遞, 再換而言之, 它不能在傳參時進行深拷貝, 它能做的只是傳指針, 同樣的道理, 如果你想將函數(shù)傳遞, 在c語法裏面也只能傳函數(shù)指針, c++11開始能用struct來模擬lambda實現(xiàn)真正傳遞函數(shù)的功能.

好, 饒了一圈, 回答剛剛那個問題, 現(xiàn)在你應(yīng)該明白了, 你這裏的形參char[]不得不退化成char*了, 其實vs的提示也暗示你這個信息了. 你的解決辦法有這麼幾種:

  1. 只用std::string/std::wstring
  2. 形參: 改成const char*/char const *

其實很早以前人們就發(fā)現(xiàn)text segment在這種情況下被修改會很危險, 但是c這貨一直不高興寫進標(biāo)準(zhǔn)來規(guī)定, 不過posix倒是弄了個strdup(3), 然後c才也跟著糊了個出來, 貌似posix不嚴格要求帶error code, 後來把may改成shall了. 那麼cppreference的表述就出錯了...或許窩該去改下cppreference...更新: 改好了...

所以跟我大聲唱:

Pointer is shit, C is shit.

Update:

補充下標(biāo)準(zhǔn)中(n4741)的wording:

clipboard.png

diff在這裏可以看到
http://www.open-std.org/jtc1/...

2017年11月8日 18:17
編輯回答
枕頭人

這個代碼本身的編譯執(zhí)行是沒有錯誤的, (在我這個默認的初始編譯器環(huán)境下), 但是, 在你的環(huán)境下, 有錯誤, 可能是因為這個原因. C2440 can occur because of conformance changes to the compiler in Visual Studio 2015 Update 3.

根據(jù)這個錯誤描述文檔, 我打開了/Zc:strictStrings這個編譯器選項, 才會出現(xiàn)你所說的錯誤, 所以, 你那里應(yīng)該是默認開啟了那個選項, 根據(jù)上面的鏈接.

你這個代碼的問題就是類型轉(zhuǎn)化的問題, 使用char sname[]="no name", 如果程序在運行時, 修改了sname字符數(shù)組的內(nèi)容, 會出問題, 如果沒有修改, 就不會有問題. 但是在寫代碼中, 這個是需要注意的.

2017年12月27日 13:36