İki dize değişmez değerini birleştirin


121

Koenig'in Accelerated C ++ programını okuyorum. "Yeni fikir, bir dizeyi ve bir dizgeyi bir araya getirmek için + kullanabileceğimizi - veya bu konuda iki dizgiyi (ancak iki dizge değişmezi değil) yazıyor.

Güzel, sanırım bu mantıklı. Şimdi bunu aydınlatmak için iki ayrı alıştırmaya geçelim.

Aşağıdaki tanımlar geçerli mi?

const string hello = "Hello";

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

Şimdi, yukarıdakileri uygulamaya çalıştım ve işe yaradı! Bu yüzden mutluydum.

Sonra bir sonraki alıştırmayı yapmaya çalıştım;

const string exclam = "!";

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

Bu işe yaramadı. Şimdi anlıyorum ki, iki dizeli değişmezi birleştiremeyeceğiniz gerçeğiyle bir ilgisi var, ancak neden işe yarayan ilk örneği elde etmeyi başardığım arasındaki anlamsal farkı anlamıyorum (", dünya" ve "değil! "iki dize değişmezi? Bu işe yaramamalı mıydı?) ama ikincisi değil.


4
const string message = "Hello" ",world" + exclam(örneğin ilkini atlamak +) gayet iyi çalışıyor.
n0rd

1
@Joe - Yapabildiğin "Hello" + ", world!"zaman neden kimse yazsın "Hello, world!"? Her zamanki gibi C ++, algılanan bir sorun için harika ve basit bir çözüm sunar. :-)
Bo Persson

2
@Bo Aklıma gelen tek şey, bir tanım kullanıyorsanız (#define)
Joe Phillips,

@Joe O zaman bile "Hello" ", world!"(olmadan +) yazma olasılığınız daha yüksektir . C ++ hakkında yapılabilecek bir dizi şikayet var, ancak burada ele alınmasının onlardan biri olduğunu sanmıyorum. Yazdığın 1 / 3 + 1.5ve şikayet ettiğinle tamamen aynı şey çünkü bölüm ayrılmaz bir bölümdü. İyi ya da kötü, çoğu dilin çalışma şekli budur.
James Kanze

2
@Bo Persson Aslında bu özellik "hello" " world" == "hello world", uzun bir dizge yazmanız gerekiyorsa ve onun pencerenizden çıkmasını istemiyorsanız veya bir satır uzunluğu kısıtlaması içinde olmak istiyorsanız kullanışlıdır. Veya dizelerden biri bir makroda tanımlanmışsa.
Dimitar Slavchev

Yanıtlar:


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

+Operatör soldan sağa olan çağrışımsal, eşdeğer parantez ifadesidir böylece:

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

Gördüğünüz gibi, iki değişmez dize "Hello"ve ",world"önce "eklenir", bu nedenle hata.

Birleştirilen ilk iki dizeden biri bir std::stringnesne olmalıdır :

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

Alternatif olarak, +ifadenin o bölümünü parantez içine alarak ikincisini ilk olarak değerlendirmeye zorlayabilirsiniz :

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

İlk örneğinizin ( hello + ",world" + "!") çalışması mantıklıdır çünkü std::string( hello) en soldaki argümanlardan biridir +. Yani +değerlendirilir, sonuç, std::stringbirleştirilmiş dizeye sahip bir nesnedir ve sonuç std::stringdaha sonra "!".


İki dize değişmez değerini kullanarak neden birleştiremeyeceğinize gelince +, bunun nedeni bir dize değişmezinin yalnızca bir karakter dizisi olmasıdır ( const char [N]neredeN null Terminatör için, dize artı bir uzunluğudur). Çoğu bağlamda bir dizi kullandığınızda, bu dizinin ilk elemanına bir göstericiye dönüştürülür.

Yani, "Hello" + ",world"yapmaya çalıştığınızda, gerçekten yapmaya çalıştığınız şey, iki const char*s'yi birbirine eklemektir , ki bu mümkün değildir (iki işaretçi eklemek ne anlama gelir?) Ve eğer olsaydı, ne yapmazdı yapmasını istedim.


O Not edebilirsiniz yanyana koyarak dize hazır bitiştirmek; örneğin, aşağıdaki ikisi eşdeğerdir:

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

Bu, birden çok satıra bölmek istediğiniz uzun bir dizgeniz varsa kullanışlıdır. Yine de dize değişmezleri olmalıdır: bu const char*işaretçiler veya const char[N]dizilerle çalışmaz .


3
Ayrıca, const string message = "Hello" + (",world"+exclam);açık parantezler nedeniyle de işe yarayacak (bu bir kelime mi?).
Chinmay Kanchi

1
İlk örneğin neden işe yaradığını const string message = ((hello + ",world") + "!");
belirtirseniz

Teşekkür ederim! Soldan sağa çağrışımla bir ilgisi olduğundan şüpheleniyordum ama emin değildim ve bu anlamsal fark bana pek mantıklı gelmiyordu. Cevabınız için minnettarım!
Arthur Collé

2
"Hello" ",world"Sözdiziminin yalnızca birden çok satıra bölünmek için değil, aynı zamanda dize değişmezlerinden biri bir makro (veya hatta her ikisi) olduğunda da yararlı olduğundan bahsedeceğim . Daha sonra birleştirme, derleme zamanında gerçekleşir.
Melebius

8

Her zaman dikkat etmelidir türleri .

Hepsi dizeleri gibi görünüyor olsa da "Hello"ve ",world"vardır değişmezleri .

Ve sizin örneğinizde exclambir std::stringnesne var.

C ++, bir std::stringnesneyi alan ve ona başka bir dize ekleyen bir operatör aşırı yüklemesine sahiptir . Bir std::stringnesneyi bir literal ile birleştirdiğinizde, değişmez için uygun döküm yapılacaktır.

Ancak iki değişmez değeri birleştirmeye çalışırsanız, derleyici iki değişmezi alan bir işleç bulamayacaktır.


Bkz std :: operatör + hangi bir bitiştirmek için teklifler aşırı yükleri std::stringbirbiriyle std::string, bir karakter dizisi veya tek bir karakter.
DavidRR

7

İkinci örneğiniz çalışmıyor çünkü operator +iki dize değişmezi yok. Bir dize değişmezinin türde değil, türde stringolduğuna dikkat edin const char *. İkinci örneğiniz şu şekilde revize ederseniz işe yarayacaktır:

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


2

1. durumda, işlem sırası nedeniyle şunları alırsınız:

(merhaba + ", dünya") + "!" merhaba + "!" ve sonunda merhaba

2. durumda, James'in belirttiği gibi, şunları elde edersiniz:

("Merhaba" + ", dünya") + 2 dize değişmezinin birleşimi olan ünlem.

Umarım açıktır :)


1

Bir dizge (veya kesin olarak std::string) ile bir karakter değişmezi arasındaki fark , ikincisi için +tanımlanmış bir operatör olmamasıdır . İkinci örneğin başarısız olmasının nedeni budur.

İlk durumda, derleyici operator+ilk argümanın a stringve ikincisi de bir karakter ( const char*) olduğu için uygun bir tane bulabilir, böylece onu kullandı. Bu işlemin sonucu yine stringa'dır, bu yüzden ona ekleme yaparken aynı numarayı tekrarlar "!".

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.