เชื่อมต่อตัวอักษรสตริงสองตัว


121

ฉันกำลังอ่าน Accelerated C ++ โดย Koenig เขาเขียนว่า "แนวคิดใหม่คือเราสามารถใช้ + เพื่อเชื่อมสตริงและสตริงลิเทอรัล - หรือสำหรับสสารนั้นสองสตริง (แต่ไม่ใช่สองสตริงลิเทอรัล)

ดีนี่ก็สมเหตุสมผลแล้วที่ฉันคิดว่า ตอนนี้เป็นแบบฝึกหัดสองแบบแยกกันเพื่อให้ความสว่างนี้

คำจำกัดความต่อไปนี้ถูกต้องหรือไม่?

const string hello = "Hello";

const string message = hello + ",world" + "!";

ตอนนี้ฉันพยายามดำเนินการข้างต้นแล้วและได้ผล! ฉันก็เลยมีความสุข

จากนั้นฉันก็พยายามทำแบบฝึกหัดต่อไป

const string exclam = "!";

const string message = "Hello" + ",world" + exclam;

สิ่งนี้ไม่ได้ผล ตอนนี้ฉันเข้าใจแล้วว่ามีบางอย่างที่เกี่ยวข้องกับการที่คุณไม่สามารถเชื่อมต่อตัวอักษรสองสตริงได้ แต่ฉันไม่เข้าใจความแตกต่างทางความหมายระหว่างสาเหตุที่ฉันจัดการให้ตัวอย่างแรกทำงานได้ (ไม่ใช่ "โลก" และ "! "ตัวอักษรสตริงสองตัวหรือไม่สิ่งนี้ควรใช้ไม่ได้หรือไม่) แต่ไม่ใช่อย่างที่สอง


4
const string message = "Hello" ",world" + exclam(เช่นการละเว้นข้อแรก+) shoud ทำงานได้ดี
n0

1
@ โจ - ทำไมใคร ๆ ก็เขียน"Hello" + ", world!"เมื่อคุณทำได้"Hello, world!". ตามปกติ C ++ มีวิธีแก้ปัญหาที่ง่ายและยอดเยี่ยมสำหรับปัญหาที่รับรู้ :-)
Bo Persson

2
@Bo สิ่งเดียวที่ฉันคิดได้คือถ้าคุณใช้คำจำกัดความ (#define)
Joe Phillips

@ โจถึงกระนั้นคุณก็มีแนวโน้มที่จะเขียน"Hello" ", world!"(โดยไม่มี+) มีข้อร้องเรียนหลายประการที่สามารถทำได้เกี่ยวกับ C ++ แต่ฉันไม่คิดว่าการจัดการที่นี่เป็นหนึ่งในนั้น มันเหมือนกับที่คุณเขียน1 / 3 + 1.5และบ่นเพราะการหารเป็นส่วนหนึ่ง เพื่อให้ดีขึ้นหรือแย่ลงนี่เป็นวิธีการทำงานของภาษาส่วนใหญ่
James Kanze

2
@Bo Persson จริงๆแล้วคุณสมบัตินี้มี"hello" " world" == "hello world"ประโยชน์ถ้าคุณต้องเขียนสตริงยาว ๆ และไม่ต้องการให้มันออกไปนอกหน้าต่างหรือคุณต้องการอยู่ในความยาวของเส้นที่ จำกัด หรือหากมีการกำหนดสตริงอย่างใดอย่างหนึ่งในมาโคร
Dimitar Slavchev

คำตอบ:


140
const string message = "Hello" + ",world" + exclam;

ตัว+ดำเนินการมีการเชื่อมโยงจากซ้ายไปขวาดังนั้นนิพจน์ในวงเล็บที่เท่ากันคือ:

const string message = (("Hello" + ",world") + exclam);

อย่างที่คุณเห็นลิเทอรัลสองสตริง"Hello"และ",world"ถูก "เพิ่ม" ก่อนจึงเกิดข้อผิดพลาด

หนึ่งในสองสตริงแรกที่เชื่อมต่อกันต้องเป็นstd::stringอ็อบเจ็กต์:

const string message = string("Hello") + ",world" + exclam;

หรือคุณสามารถบังคับ+ให้ประเมินวินาทีก่อนโดยการใส่วงเล็บส่วนนั้นของนิพจน์:

const string message = "Hello" + (",world" + exclam);

มันทำให้รู้สึกว่าตัวอย่างแรกของคุณ ( hello + ",world" + "!") ทำงานเพราะstd::string( hello) +เป็นหนึ่งในข้อโต้แย้งไปซ้ายสุด ที่+ได้รับการประเมินผลลัพธ์คือstd::stringอ็อบเจ็กต์ที่มีสตริงที่ต่อกันและผลลัพธ์std::stringนั้นจะถูกเชื่อมต่อกับ"!".


สำหรับเหตุผลที่คุณไม่สามารถเชื่อมสองตัวอักษรของสตริงที่ใช้+ก็เป็นเพราะตัวอักษรสตริงเป็นเพียงอาร์เรย์ของตัวอักษร (กconst char [N]ที่Nมีความยาวของสตริงบวกหนึ่งสำหรับเทอร์มิโมฆะ) เมื่อคุณใช้อาร์เรย์ในบริบทส่วนใหญ่อาร์เรย์จะถูกแปลงเป็นตัวชี้ไปยังองค์ประกอบเริ่มต้น

ดังนั้นเมื่อคุณพยายามทำ"Hello" + ",world"สิ่งที่คุณพยายามทำจริงๆคือเพิ่มสองconst char*ตัวเข้าด้วยกันซึ่งเป็นไปไม่ได้ (การบวกสองพอยน์เตอร์เข้าด้วยกันหมายความว่าอย่างไร) และถ้ามันจะไม่ทำอย่างที่คุณ อยากให้ทำ


โปรดทราบว่าคุณสามารถเชื่อมต่อตัวอักษรสตริงได้โดยวางไว้ข้างๆกัน ตัวอย่างเช่นสองสิ่งต่อไปนี้เทียบเท่า:

"Hello" ",world"
"Hello,world"

สิ่งนี้มีประโยชน์หากคุณมีลิเทอรัลสตริงแบบยาวที่คุณต้องการแยกย่อยเป็นหลายบรรทัด พวกเขาจะต้องเป็นตัวอักษรสตริงแม้ว่าสิ่งนี้จะใช้ไม่ได้กับพconst char*อยน์เตอร์หรือconst char[N]อาร์เรย์


3
นอกจากนี้const string message = "Hello" + (",world"+exclam);จะได้ผลเช่นกันเนื่องจากมีการใส่วงเล็บอย่างชัดเจน (เป็นคำหรือไม่)
Chinmay Kanchi

1
อาจจะสมบูรณ์ยิ่งขึ้นหากคุณชี้ให้เห็นว่าเหตุใดตัวอย่างแรกจึงใช้ได้ผล:const string message = ((hello + ",world") + "!");
Mark Ransom

ขอบคุณ! ฉันสงสัยว่ามันเกี่ยวข้องกับการเชื่อมโยงจากซ้ายไปขวา แต่ไม่แน่ใจและความแตกต่างทางความหมายนี้ไม่สมเหตุสมผลกับฉันมากนัก ฉันขอขอบคุณคำตอบ!
Arthur Collé

2
ฉันจะพูดถึง"Hello" ",world"ไวยากรณ์นั้นมีประโยชน์ไม่เพียง แต่สำหรับการแบ่งออกเป็นหลายบรรทัด แต่ยังรวมถึงเมื่อตัวอักษรสตริงตัวใดตัวหนึ่งเป็นมาโคร (หรือแม้แต่ทั้งสองอย่าง) จากนั้นการเรียงต่อกันจะเกิดขึ้นในเวลาคอมไพล์
Melebius

8

คุณควรใส่ใจกับประเภทต่างๆเสมอ

ถึงแม้ว่าพวกเขาทั้งหมดดูเหมือนสตริง"Hello"และ",world"มีตัวอักษร

และในตัวอย่างของคุณexclamคือstd::stringวัตถุ

C ++ มีตัวดำเนินการโอเวอร์โหลดที่รับstd::stringวัตถุและเพิ่มสตริงอื่นเข้าไป เมื่อคุณเชื่อมstd::stringวัตถุเข้ากับตัวอักษรมันจะทำให้การหล่อที่เหมาะสมสำหรับตัวอักษร

แต่ถ้าคุณพยายามเชื่อมต่อตัวอักษรสองตัวคอมไพเลอร์จะไม่สามารถค้นหาตัวดำเนินการที่ใช้ตัวอักษรสองตัวได้


ดูstd :: operator +ซึ่งมีโอเวอร์โหลดสำหรับการเชื่อมต่อ a std::stringกับstd::stringอาร์เรย์อักขระอื่นหรืออักขระเดี่ยว
DavidRR

7

ตัวอย่างที่สองของคุณใช้ไม่ได้เนื่องจากไม่มีoperator +ตัวอักษรสตริงสองตัว โปรดทราบว่าสตริงลิเทอรัลไม่ใช่ประเภทstringแต่เป็นชนิดconst char *แทน ตัวอย่างที่สองของคุณจะใช้งานได้หากคุณแก้ไขดังนี้:

const string message = string("Hello") + ",world" + exclam;


2

ในกรณีที่ 1 เนื่องจากลำดับการดำเนินการที่คุณได้รับ:

(สวัสดี + ", โลก") + "!" ซึ่งเปลี่ยนเป็นสวัสดี + "!" และสุดท้ายสวัสดี

ในกรณีที่ 2 ตามที่ James กล่าวไว้คุณจะได้รับ:

("Hello" + ", world") + exclam ซึ่งเป็นการต่อกันของตัวอักษร 2 สตริง

หวังว่าจะชัดเจน :)


1

ความแตกต่างระหว่างสตริง (หรือเพื่อความแม่นยำstd::string) และลิเทอรัลของอักขระคือในส่วนหลังไม่มี+การกำหนดตัวดำเนินการ นี่คือสาเหตุที่ตัวอย่างที่สองล้มเหลว

ในกรณีแรกคอมไพลเลอร์สามารถหาค่าที่เหมาะสมได้operator+โดยอาร์กิวเมนต์แรกคือ a stringและตัวที่สอง a character literal ( const char*) ดังนั้นจึงใช้สิ่งนั้น ผลลัพธ์ของการดำเนินการนั้นคือ a อีกครั้งstringดังนั้นมันจะทำเคล็ดลับเดียวกันซ้ำเมื่อเพิ่ม"!"เข้าไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.