มันจะดีกว่าใน C ++ ที่จะผ่านค่าหรือผ่านการอ้างอิงคงที่?


213

มันจะดีกว่าใน C ++ ที่จะผ่านค่าหรือผ่านการอ้างอิงคงที่?

ฉันสงสัยว่าวิธีไหนดีกว่ากัน ฉันรู้ว่าการส่งผ่านโดยการอ้างอิงอย่างต่อเนื่องควรให้ประสิทธิภาพที่ดีขึ้นในโปรแกรมเพราะคุณไม่ได้ทำสำเนาของตัวแปร


เกี่ยวข้อง: stackoverflow.com/questions/2139224/…
sbi

คำตอบ:


203

มันเคยได้รับการแนะนำโดยทั่วไปปฏิบัติที่ดีที่สุด1ในการใช้งานผ่านโดนโทษ const สำหรับทุกประเภทยกเว้นประเภท builtin ( char, int, doubleฯลฯ ) สำหรับ iterators และฟังก์ชั่นสำหรับวัตถุ (lambdas เรียนมาจากstd::*_function)

นี่คือความจริงโดยเฉพาะอย่างยิ่งก่อนการดำรงอยู่ของความหมายย้าย เหตุผลนั้นง่าย: ถ้าคุณส่งผ่านค่าจะต้องทำสำเนาของวัตถุและยกเว้นวัตถุขนาดเล็กมากสิ่งนี้จะมีราคาแพงกว่าการส่งผ่านการอ้างอิงเสมอ

ด้วย C ++ 11 เราได้รับความหมายย้าย สรุปย้ายความหมายอนุญาตให้ในบางกรณีวัตถุสามารถส่งผ่าน "ตามค่า" โดยไม่ต้องคัดลอก โดยเฉพาะอย่างยิ่งเป็นกรณีนี้เมื่อวัตถุที่คุณจะผ่านเป็นrvalue

ในตัวมันเองการเคลื่อนย้ายวัตถุก็ยังมีค่าใช้จ่ายอย่างน้อยก็ผ่านการอ้างอิง อย่างไรก็ตามในหลายกรณีฟังก์ชั่นจะคัดลอกภายในวัตถุอยู่แล้ว - เช่นมันจะเป็นเจ้าของอาร์กิวเมนต์ 2

ในสถานการณ์เหล่านี้เรามีการแลกเปลี่ยน (ง่าย) ดังต่อไปนี้:

  1. เราสามารถส่งผ่านวัตถุโดยการอ้างอิงแล้วคัดลอกภายใน
  2. เราสามารถผ่านวัตถุตามค่า

“ ผ่านค่า” ยังคงเป็นสาเหตุให้วัตถุถูกคัดลอกเว้นแต่ว่าวัตถุนั้นเป็นค่า rvalue ในกรณีของค่า rvalue วัตถุสามารถถูกย้ายแทนดังนั้นในกรณีที่สองไม่ได้“ คัดลอกแล้วย้าย” อีกต่อไปทันที แต่“ ย้ายจากนั้น (อาจ) ย้ายอีกครั้ง”

สำหรับวัตถุขนาดใหญ่ที่ใช้ก่อสร้างย้ายที่เหมาะสม (เช่นเวกเตอร์สตริง ... ), กรณีที่สองเป็นแล้วอย่างมากมายมีประสิทธิภาพมากขึ้นกว่าครั้งแรก ดังนั้นจึงขอแนะนำให้ใช้ผ่านค่าถ้าฟังก์ชั่นใช้เวลาความเป็นเจ้าของของการโต้แย้งและถ้าชนิดของวัตถุที่เคลื่อนไหวสนับสนุนที่มีประสิทธิภาพ


บันทึกประวัติศาสตร์:

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

ในทางทฤษฎี ในทางปฏิบัติคอมไพเลอร์ไม่สามารถเปลี่ยนแปลงสิ่งนี้ได้ตลอดเวลาโดยไม่ทำลายส่วนต่อประสานไบนารีของฟังก์ชัน ในบางกรณีพิเศษ (เมื่อฟังก์ชั่นอินไลน์) สำเนาจะถูกนำออกมาจริง ๆ หากคอมไพเลอร์สามารถเข้าใจได้ว่าวัตถุดั้งเดิมจะไม่ถูกเปลี่ยนผ่านการดำเนินการในฟังก์ชั่น

แต่โดยทั่วไปแล้วคอมไพเลอร์ไม่สามารถระบุสิ่งนี้ได้และการกำเนิดความหมายของการย้ายใน C ++ ทำให้การเพิ่มประสิทธิภาพนี้มีความเกี่ยวข้องน้อยลง


1เช่นในสกอตต์เมเยอร์สที่มีประสิทธิภาพ C ++

2สิ่งนี้มักจะเป็นจริงสำหรับผู้สร้างวัตถุซึ่งอาจรับข้อโต้แย้งและเก็บไว้ภายในเพื่อเป็นส่วนหนึ่งของสถานะของวัตถุที่สร้างขึ้น


อืม ... ฉันไม่แน่ใจว่ามันคุ้มค่าที่จะส่งต่อโดยอ้างอิง double-s
sergtk

3
ตามปกติเพิ่มความช่วยเหลือที่นี่ boost.org/doc/libs/1_37_0/libs/utility/call_traits.htmมีเนื้อหาเทมเพลตที่จะคิดออกโดยอัตโนมัติเมื่อประเภทเป็นประเภทบิวอิน (มีประโยชน์สำหรับเทมเพลตซึ่งบางครั้งคุณไม่สามารถรู้ได้อย่างง่ายดาย)
CesarB

13
คำตอบนี้พลาดจุดสำคัญ เพื่อหลีกเลี่ยงการแบ่งคุณจะต้องผ่านการอ้างอิง (const หรืออย่างอื่น) ดูstackoverflow.com/questions/274626/…
ChrisN

6
@Chris: ถูกต้อง ฉันทิ้งส่วนต่าง ๆ ของความแตกต่างออกไปเพราะนั่นเป็นความหมายที่แตกต่างอย่างสิ้นเชิง ฉันเชื่อว่า OP (หมายถึง) หมายถึงการโต้แย้งโดยผ่านค่า เมื่อจำเป็นต้องมีความหมายอื่นคำถามก็ไม่ได้ก่อให้เกิด
Konrad Rudolph

98

แก้ไข:บทความใหม่โดย Dave Abrahams ใน cpp-next:

ต้องการความเร็วหรือไม่ ผ่านค่า


การส่งผ่านค่าสำหรับ structs ที่การคัดลอกราคาถูกมีข้อดีเพิ่มเติมที่คอมไพเลอร์อาจคิดว่าวัตถุนั้นไม่ใช่นามแฝง (ไม่ใช่วัตถุเดียวกัน) การใช้ Pass-by-Reference คอมไพเลอร์ไม่สามารถคาดเดาได้เสมอ ตัวอย่างง่ายๆ:

foo * f;

void bar(foo g) {
    g.i = 10;
    f->i = 2;
    g.i += 5;
}

คอมไพเลอร์สามารถเพิ่มประสิทธิภาพให้เป็น

g.i = 15;
f->i = 2;

เนื่องจากรู้ว่า f และ g ไม่ได้แชร์ตำแหน่งเดียวกัน ถ้า g เป็นข้อมูลอ้างอิง (foo &) คอมไพเลอร์ก็ไม่สามารถคาดเดาได้ เนื่องจาก gi สามารถเป็น aliased ได้โดย f-> i และต้องมีค่าเป็น 7 ดังนั้นคอมไพเลอร์จะต้องดึงค่าใหม่ของ gi จากหน่วยความจำอีกครั้ง

สำหรับกฎ pratical เพิ่มเติมนี่คือชุดของกฎที่ดีที่พบในบทความMove Constructors (ขอแนะนำให้อ่าน)

  • หากฟังก์ชั่นตั้งใจที่จะเปลี่ยนอาร์กิวเมนต์เป็นผลข้างเคียงให้ดำเนินการโดยการอ้างอิงที่ไม่ใช่แบบ const
  • หากฟังก์ชั่นไม่ได้แก้ไขข้อโต้แย้งของมันและข้อโต้แย้งเป็นประเภทดั้งเดิมให้รับมันด้วยค่า
  • มิฉะนั้นจะใช้มันโดยอ้างอิง const ยกเว้นในกรณีต่อไปนี้
    • หากฟังก์ชั่นนั้นจะต้องทำสำเนาของการอ้างอิง const อยู่ให้ทำตามค่า

"ดั้งเดิม" ด้านบนหมายถึงชนิดข้อมูลขนาดเล็กโดยทั่วไปที่มีความยาวไม่กี่ไบต์และไม่ polymorphic (ตัววนซ้ำวัตถุฟังก์ชัน ฯลฯ ... ) หรือมีราคาแพงในการคัดลอก ในบทความนั้นมีกฎอีกข้อหนึ่ง แนวคิดคือบางครั้งเราต้องการทำสำเนา (ในกรณีที่ไม่สามารถแก้ไขข้อโต้แย้งได้) และบางครั้งก็ไม่ต้องการ (ในกรณีที่ต้องการใช้อาร์กิวเมนต์เองในฟังก์ชันหากอาร์กิวเมนต์เป็นแบบชั่วคราวอยู่แล้ว , ตัวอย่างเช่น). กระดาษอธิบายรายละเอียดวิธีการที่สามารถทำได้ ใน C ++ 1x เทคนิคนั้นสามารถนำมาใช้ได้กับการสนับสนุนทางภาษา ก่อนหน้านั้นฉันจะทำตามกฎข้างต้น

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

my::string uppercase(my::string s) { /* change s and return it */ }

อย่างไรก็ตามหากคุณไม่จำเป็นต้องเปลี่ยนพารามิเตอร์ให้ดำเนินการโดยอ้างอิงกับ const:

bool all_uppercase(my::string const& s) { 
    /* check to see whether any character is uppercase */
}

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

bool try_parse(T text, my::string &out) {
    /* try to parse, write result into out */
}

ฉันพบกฎของคุณดี แต่ฉันไม่แน่ใจเกี่ยวกับส่วนแรกที่คุณพูดคุยเกี่ยวกับการไม่ผ่านมันเป็นผู้อ้างอิงจะเร่งมันขึ้น ใช่แน่นอน แต่ไม่ได้ผ่านบางสิ่งบางอย่างในฐานะผู้อ้างอิงของการเพิ่มประสิทธิภาพเท่านั้นไม่สมเหตุสมผลเลย ถ้าคุณต้องการเปลี่ยนวัตถุสแต็กที่คุณกำลังผ่านให้ทำโดยอ้างอิง ถ้าคุณไม่ผ่านมันตามตัวอักษร ถ้าคุณไม่ต้องการเปลี่ยนมันให้ส่งมันเป็น const-ref การเพิ่มประสิทธิภาพที่มาพร้อมกับการส่งผ่านค่าไม่ควรสำคัญเนื่องจากคุณได้รับสิ่งอื่น ๆ เมื่อผ่านการอ้างอิง ฉันไม่เข้าใจ "ต้องการความเร็วหรือไม่" SICE ถ้าคุณที่จะดำเนินการสหกรณ์ที่คุณจะผ่านค่าต่อไป ..
chikuba

โยฮันเนส: ฉันชอบบทความนั้นเมื่อฉันอ่านมัน แต่ฉันรู้สึกผิดหวังเมื่อฉันลองมัน รหัสนี้ล้มเหลวทั้งใน GCC และ MSVC ฉันพลาดอะไรบางอย่างหรือไม่ได้ผลในทางปฏิบัติ?
user541686

ฉันไม่คิดว่าฉันเห็นด้วยว่าถ้าคุณต้องการทำสำเนาอยู่ดีคุณจะส่งมันตามมูลค่า (แทนที่จะเป็น const อ้างอิง) จากนั้นย้ายมัน ดูมันด้วยวิธีนี้มีประสิทธิภาพมากขึ้นคัดลอกและย้าย (คุณสามารถมี 2 สำเนาถ้าคุณส่งมันไปข้างหน้า) หรือเพียงแค่สำเนา ใช่มีบางกรณีพิเศษที่ด้านใดด้านหนึ่ง แต่ถ้าข้อมูลของคุณไม่สามารถย้ายได้ (เช่น POD ที่มีจำนวนเต็มเป็นตัน) ไม่จำเป็นต้องทำสำเนาเพิ่มเติม
ไอออน Todirel

2
Mehrdad ไม่แน่ใจว่าสิ่งที่คุณคาดหวัง แต่ผลงานรหัสตามที่คาดไว้
ไอออน Todirel

ฉันจะพิจารณาความจำเป็นของการคัดลอกเพียงเพื่อโน้มน้าวใจคอมไพเลอร์ว่าประเภทไม่ทับซ้อนกันขาดในภาษา ฉันควรใช้ GCC __restrict__(ซึ่งสามารถใช้อ้างอิง) ได้มากกว่าทำสำเนามากเกินไป C ++ มาตรฐานที่แย่เกินไปไม่ได้ใช้restrictคำสำคัญของ C99
Ruslan

12

ขึ้นอยู่กับประเภท คุณกำลังเพิ่มค่าใช้จ่ายเล็ก ๆ ที่ต้องทำการอ้างอิงและการอ้างอิง สำหรับประเภทที่มีขนาดเท่ากันหรือเล็กกว่าพอยน์เตอร์ที่ใช้ ctor คัดลอกเริ่มต้นมันอาจจะเร็วกว่าที่จะผ่านค่า


สำหรับประเภทที่ไม่ใช่เจ้าของภาษาคุณอาจ (ขึ้นอยู่กับว่าคอมไพเลอร์ปรับรหัสให้เหมาะสม) รับประสิทธิภาพเพิ่มขึ้นได้อย่างไรโดยใช้การอ้างอิง const แทนการอ้างอิงเพียงอย่างเดียว
OJ

9

เมื่อมีการชี้ให้เห็นมันก็ขึ้นอยู่กับประเภท สำหรับชนิดข้อมูลในตัววิธีที่ดีที่สุดคือส่งผ่านค่า แม้แต่โครงสร้างที่มีขนาดเล็กมากเช่น ints คู่หนึ่งสามารถทำงานได้ดีขึ้นโดยการส่งผ่านค่า

นี่คือตัวอย่างสมมติว่าคุณมีค่าจำนวนเต็มและคุณต้องการส่งผ่านไปยังรูทีนอื่น หากค่านั้นได้รับการปรับให้เหมาะสมเพื่อเก็บไว้ในรีจิสเตอร์ถ้าคุณต้องการส่งผ่านการอ้างอิงก่อนอื่นจะต้องถูกเก็บไว้ในหน่วยความจำก่อนจากนั้นตัวชี้ไปยังหน่วยความจำนั้นบนสแต็กเพื่อทำการโทร ถ้ามันถูกส่งผ่านโดยค่าทั้งหมดที่จำเป็นต้องมีคือการลงทะเบียนผลักลงบนสแต็ก (รายละเอียดมีความซับซ้อนเล็กน้อยกว่าที่ได้รับจากระบบการโทรและ CPU ที่แตกต่างกัน)

หากคุณกำลังเขียนโปรแกรมแม่แบบคุณมักจะถูกบังคับให้ผ่านการอ้างอิง const เนื่องจากคุณไม่ทราบประเภทที่ถูกส่งเข้ามาการผ่านบทลงโทษสำหรับการส่งสิ่งที่ไม่ดีตามมูลค่านั้นแย่กว่าโทษของการผ่านประเภทในตัว โดยอ้างอิง const


หมายเหตุเกี่ยวกับคำศัพท์: struct ที่มีล้าน ints ยังคงเป็น "ประเภท POD" เป็นไปได้ว่าคุณหมายถึง 'สำหรับประเภทในตัวควรส่งผ่านค่า'
Steve Jessop

6

นี่คือสิ่งที่ฉันทำงานตามปกติเมื่อออกแบบอินเตอร์เฟสของฟังก์ชันที่ไม่ใช่เทมเพลต:

  1. ผ่านค่าหากฟังก์ชันไม่ต้องการแก้ไขพารามิเตอร์และค่าถูกคัดลอก (int, double, float, char, bool, etc ... สังเกตว่า std :: string, std :: vector, และส่วนที่เหลือ ของคอนเทนเนอร์ในไลบรารีมาตรฐานไม่ใช่)

  2. ส่งผ่านตัวชี้ const หากค่ามีราคาแพงในการคัดลอกและฟังก์ชั่นไม่ต้องการแก้ไขค่าที่ชี้ไปและ NULL เป็นค่าที่ฟังก์ชันจัดการ

  3. ผ่านตัวชี้ที่ไม่ใช่ const ถ้าค่ามีราคาแพงในการคัดลอกและฟังก์ชันต้องการแก้ไขค่าที่ชี้ไปและ NULL เป็นค่าที่ฟังก์ชันจัดการ

  4. ผ่านการอ้างอิง const เมื่อค่ามีราคาแพงในการคัดลอกและฟังก์ชั่นไม่ต้องการแก้ไขค่าที่อ้างถึงและ NULL จะไม่เป็นค่าที่ถูกต้องหากใช้ตัวชี้แทน

  5. ผ่านการอ้างอิงที่ไม่ใช่ const เมื่อค่ามีราคาแพงในการคัดลอกและฟังก์ชันต้องการแก้ไขค่าที่อ้างถึงและ NULL จะไม่ใช่ค่าที่ถูกต้องหากใช้ตัวชี้แทน


เพิ่มstd::optionalไปที่รูปภาพและคุณไม่ต้องการตัวชี้อีกต่อไป
Violet Giraffe

5

ดูเหมือนคุณจะได้คำตอบ การส่งผ่านค่ามีราคาแพง แต่ให้สำเนาเพื่อทำงานหากคุณต้องการ


ฉันไม่แน่ใจว่าทำไมสิ่งนี้จึงถูกโหวต? มันสมเหตุสมผลสำหรับฉัน หากคุณต้องการค่าที่เก็บไว้ในปัจจุบันให้ผ่านค่านั้น ถ้าไม่ผ่านการอ้างอิง
Totty

4
มันขึ้นอยู่กับประเภททั้งหมด การทำชนิด POD (ข้อมูลเก่าธรรมดา) โดยการอ้างอิงสามารถลดประสิทธิภาพโดยการทำให้หน่วยความจำเข้าถึงมากขึ้น
Torlack

1
เห็นได้ชัดว่าการผ่าน int โดยการอ้างอิงไม่ได้ช่วยอะไรเลย! ฉันคิดว่าคำถามหมายถึงสิ่งที่ใหญ่กว่าตัวชี้
GeekyMonkey

4
เห็นได้ชัดว่าฉันเห็นรหัสจำนวนมากโดยผู้ที่ไม่เข้าใจวิธีการทำงานของคอมพิวเตอร์ผ่านสิ่งต่าง ๆ โดยอ้างอิงเพราะพวกเขาบอกว่าเป็นสิ่งที่ดีที่สุดที่จะทำ
Torlack

4

เป็นกฎที่ผ่านไปโดยอ้างอิง const จะดีกว่า แต่ถ้าคุณต้องการแก้ไขอาร์กิวเมนต์ของฟังก์ชันในเครื่องคุณควรใช้การผ่านค่า สำหรับประเภทพื้นฐานบางประเภทประสิทธิภาพโดยทั่วไปจะเหมือนกันทั้งสำหรับการส่งผ่านค่าและอ้างอิง การอ้างอิงตัวชี้ภายในโดยพอยน์เตอร์จริงๆแล้วนั่นคือสาเหตุที่คุณสามารถคาดหวังได้ว่าอินสแตนซ์สำหรับพอยน์เตอร์การส่งผ่านทั้งสองจะเหมือนกันในแง่ของประสิทธิภาพการทำงานหรือแม้แต่การส่งผ่านค่า


หากคุณต้องการแก้ไขสำเนาของพารามิเตอร์ของ callee คุณสามารถทำสำเนาในรหัสที่เรียกว่าแทนที่จะส่งผ่านค่า IMO โดยทั่วไปคุณไม่ควรเลือก API ตามรายละเอียดการใช้งานเช่นนั้นแหล่งที่มาของรหัสการโทรนั้นเป็นวิธีเดียวกัน แต่ไม่ได้มีรหัสวัตถุ
Steve Jessop

ถ้าคุณผ่านการคัดลอกค่าจะถูกสร้างขึ้น และ IMO ไม่ว่าคุณจะสร้างสำเนาด้วยวิธีใด: ผ่านการโต้แย้งโดยผ่านค่าหรือในพื้นที่ - นี่คือสิ่งที่เกี่ยวข้องกับ C ++ แต่จากมุมมองของการออกแบบฉันเห็นด้วยกับคุณ แต่ฉันอธิบายคุณลักษณะ C ++ ที่นี่เท่านั้นและอย่าแตะต้องการออกแบบ
sergtk

1

ในฐานะที่เป็นกฎของหัวแม่มือค่าสำหรับประเภทที่ไม่ใช่ชั้นเรียนและการอ้างอิง const สำหรับชั้นเรียน ถ้าชั้นเรียนมีขนาดเล็กจริง ๆ น่าจะดีกว่าที่จะผ่านค่า แต่ความแตกต่างนั้นน้อยที่สุด สิ่งที่คุณต้องการหลีกเลี่ยงจริง ๆ คือผ่านคลาสมโหฬารโดยมีค่าและมีการทำซ้ำทั้งหมด - นี้จะสร้างความแตกต่างใหญ่ถ้าคุณผ่านพูด std :: vector กับองค์ประกอบบางอย่างในนั้น


ความเข้าใจของฉันคือการstd::vectorจัดสรรสิ่งของในกองและวัตถุเวกเตอร์นั้นไม่เคยเติบโต โอ้เดี๋ยวก่อน หากการดำเนินการทำให้สำเนาของเวกเตอร์ที่จะทำ แต่ในความเป็นจริงมันจะไปและทำซ้ำองค์ประกอบทั้งหมด มันจะไม่ดี
Steven Lu

1
ใช่นั่นคือสิ่งที่ฉันคิด sizeof(std::vector<int>)เป็นค่าคงที่ แต่การส่งผ่านค่าจะยังคงคัดลอกเนื้อหาในกรณีที่ไม่มีคอมไพเลอร์ใด ๆ
ปีเตอร์

1

ผ่านค่าขนาดเล็ก

ผ่านการอ้างอิง const สำหรับประเภทใหญ่ (คำจำกัดความของขนาดใหญ่อาจแตกต่างกันระหว่างเครื่อง) BUT ใน C ++ 11 ส่งผ่านค่าถ้าคุณจะใช้ข้อมูลเนื่องจากคุณสามารถใช้ประโยชน์จากการย้ายความหมาย ตัวอย่างเช่น:

class Person {
 public:
  Person(std::string name) : name_(std::move(name)) {}
 private:
  std::string name_;
};

ตอนนี้รหัสโทรจะทำ:

Person p(std::string("Albert"));

และมีเพียงวัตถุเดียวเท่านั้นที่จะถูกสร้างและย้ายไปยังสมาชิกname_ในคลาสPersonโดยตรง หากคุณผ่านการอ้างอิง const name_สำเนาจะต้องมีการสร้างขึ้นมาเพื่อใส่ลงใน


-5

ความแตกต่างง่าย ๆ : - ในฟังก์ชั่นเรามีพารามิเตอร์อินพุตและเอาต์พุตดังนั้นหากพารามิเตอร์อินพุตและเอาต์พุตของคุณเหมือนกันให้ใช้การอ้างอิงโดยการอ้างอิงอื่นหากพารามิเตอร์อินพุตและเอาต์พุตแตกต่างกัน

ตัวอย่าง void amount(int account , int deposit , int total )

พารามิเตอร์อินพุต: บัญชี, พารามิเตอร์การส่งออกเงินฝาก: ทั้งหมด

อินพุตและเอ้าท์คือการใช้งานที่แตกต่างกันโดย vaule

  1. void amount(int total , int deposit )

ยอดรวมเงินฝากทั้งหมด

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