Kelebihan Beban Fungsi
C++ memungkinkan Anda menentukan lebih dari satu fungsi dengan nama yang sama dalam cakupan yang sama. Fungsi-fungsi ini disebut fungsi yang kelebihan beban, atau kelebihan beban. Fungsi yang kelebihan beban memungkinkan Anda menyediakan semantik yang berbeda untuk fungsi, tergantung pada jenis dan jumlah argumennya.
Misalnya, pertimbangkan print
fungsi yang mengambil std::string
argumen. Fungsi ini mungkin melakukan tugas yang sangat berbeda dari fungsi yang mengambil argumen jenis double
. Kelebihan beban membuat Anda tidak perlu menggunakan nama seperti print_string
atau print_double
. Pada waktu kompilasi, pengkompilasi memilih kelebihan beban mana yang akan digunakan berdasarkan jenis dan jumlah argumen yang diteruskan oleh pemanggil. Jika Anda memanggil print(42.0)
, maka void print(double d)
fungsi dipanggil. Jika Anda memanggil print("hello world")
, maka void print(std::string)
kelebihan beban dipanggil.
Anda dapat membebani fungsi anggota dan fungsi bebas. Tabel berikut menunjukkan bagian mana dari deklarasi fungsi yang digunakan C++ untuk membedakan antara grup fungsi dengan nama yang sama dalam cakupan yang sama.
Pertimbangan Kelebihan Beban
Elemen deklarasi fungsi | Digunakan untuk kelebihan beban? |
---|---|
Jenis pengembalian fungsi | No |
Jumlah argumen | Ya |
Jenis argumen | Ya |
Kehadiran atau tidak adanya elipsis | Ya |
Penggunaan typedef nama |
No |
Batas array yang tidak ditentukan | No |
const atau volatile |
Ya, saat diterapkan ke seluruh fungsi |
Kualifikasi referensi (& dan && ) |
Ya |
Contoh
Contoh berikut mengilustrasikan bagaimana Anda dapat menggunakan kelebihan beban fungsi:
// function_overloading.cpp
// compile with: /EHsc
#include <iostream>
#include <math.h>
#include <string>
// Prototype three print functions.
int print(std::string s); // Print a string.
int print(double dvalue); // Print a double.
int print(double dvalue, int prec); // Print a double with a
// given precision.
using namespace std;
int main(int argc, char *argv[])
{
const double d = 893094.2987;
if (argc < 2)
{
// These calls to print invoke print( char *s ).
print("This program requires one argument.");
print("The argument specifies the number of");
print("digits precision for the second number");
print("printed.");
exit(0);
}
// Invoke print( double dvalue ).
print(d);
// Invoke print( double dvalue, int prec ).
print(d, atoi(argv[1]));
}
// Print a string.
int print(string s)
{
cout << s << endl;
return cout.good();
}
// Print a double in default precision.
int print(double dvalue)
{
cout << dvalue << endl;
return cout.good();
}
// Print a double in specified precision.
// Positive numbers for precision indicate how many digits
// precision after the decimal point to show. Negative
// numbers for precision indicate where to round the number
// to the left of the decimal point.
int print(double dvalue, int prec)
{
// Use table-lookup for rounding/truncation.
static const double rgPow10[] = {
10E-7, 10E-6, 10E-5, 10E-4, 10E-3, 10E-2, 10E-1,
10E0, 10E1, 10E2, 10E3, 10E4, 10E5, 10E6 };
const int iPowZero = 6;
// If precision out of range, just print the number.
if (prec < -6 || prec > 7)
{
return print(dvalue);
}
// Scale, truncate, then rescale.
dvalue = floor(dvalue / rgPow10[iPowZero - prec]) *
rgPow10[iPowZero - prec];
cout << dvalue << endl;
return cout.good();
}
Kode sebelumnya menunjukkan kelebihan beban print
fungsi dalam cakupan file.
Argumen default tidak dianggap sebagai bagian dari jenis fungsi. Oleh karena itu, ini tidak digunakan dalam memilih fungsi yang kelebihan beban. Dua fungsi yang hanya berbeda dalam argumen defaultnya dianggap sebagai beberapa definisi daripada fungsi yang kelebihan beban.
Argumen default tidak dapat disediakan untuk operator yang kelebihan beban.
Pencocokan argumen
Pengkompilasi memilih fungsi kelebihan beban yang akan dipanggil berdasarkan kecocokan terbaik di antara deklarasi fungsi dalam cakupan saat ini ke argumen yang disediakan dalam panggilan fungsi. Jika fungsi yang sesuai ditemukan, fungsi tersebut dipanggil. "Cocok" dalam konteks ini berarti:
Kecocokan yang tepat ditemukan.
Konversi sepele dilakukan.
Promosi integral dilakukan.
Konversi standar ke jenis argumen yang diinginkan ada.
Konversi yang ditentukan pengguna (baik operator konversi atau konstruktor) ke jenis argumen yang diinginkan ada.
Argumen yang diwakili oleh elipsis ditemukan.
Pengkompilasi membuat sekumpulan fungsi kandidat untuk setiap argumen. Fungsi kandidat adalah fungsi di mana argumen aktual dalam posisi tersebut dapat dikonversi ke jenis argumen formal.
Sekumpulan "fungsi pencocokan terbaik" dibangun untuk setiap argumen, dan fungsi yang dipilih adalah persimpangan semua set. Jika persimpangan berisi lebih dari satu fungsi, kelebihan beban bersifat ambigu dan menghasilkan kesalahan. Fungsi yang akhirnya dipilih selalu cocok dengan yang lebih baik daripada setiap fungsi lain dalam grup untuk setidaknya satu argumen. Jika tidak ada pemenang yang jelas, panggilan fungsi menghasilkan kesalahan kompilator.
Pertimbangkan deklarasi berikut (fungsi ditandai Variant 1
, , Variant 2
dan Variant 3
, untuk identifikasi dalam diskusi berikut):
Fraction &Add( Fraction &f, long l ); // Variant 1
Fraction &Add( long l, Fraction &f ); // Variant 2
Fraction &Add( Fraction &f, Fraction &f ); // Variant 3
Fraction F1, F2;
Pertimbangkan pernyataan berikut:
F1 = Add( F2, 23 );
Pernyataan sebelumnya membangun dua set:
Set 1: Fungsi kandidat yang memiliki argumen jenis pertama Fraction |
Set 2: Fungsi kandidat yang argumen keduanya dapat dikonversi ke jenis int |
---|---|
Varian 1 | Varian 1 (int dapat dikonversi ke long menggunakan konversi standar) |
Varian 3 |
Fungsi dalam Set 2 adalah fungsi yang memiliki konversi implisit dari jenis parameter aktual ke jenis parameter formal. Salah satu fungsi tersebut memiliki "biaya" terkecil untuk mengonversi jenis parameter aktual ke jenis parameter formal yang sesuai.
Persimpangan kedua set ini adalah Varian 1. Contoh panggilan fungsi ambigu adalah:
F1 = Add( 3, 6 );
Panggilan fungsi sebelumnya membangun set berikut:
Set 1: Fungsi Kandidat yang Memiliki Argumen Tipe Pertama int |
Set 2: Fungsi Kandidat yang Memiliki Argumen Tipe Kedua int |
---|---|
Varian 2 (int dapat dikonversi ke long menggunakan konversi standar) |
Varian 1 (int dapat dikonversi ke long menggunakan konversi standar) |
Karena persimpangan kedua set ini kosong, pengkompilasi menghasilkan pesan kesalahan.
Untuk pencocokan argumen, fungsi dengan argumen default n diperlakukan sebagai n+1 fungsi terpisah, masing-masing dengan jumlah argumen yang berbeda.
Elipsis (...
) bertindak sebagai kartubebas; cocok dengan argumen aktual apa pun. Ini dapat menyebabkan banyak set ambigu, jika Anda tidak merancang set fungsi yang kelebihan beban dengan perawatan ekstrem.
Catatan
Ambiguitas fungsi yang kelebihan beban tidak dapat ditentukan sampai panggilan fungsi ditemui. Pada titik itu, set dibangun untuk setiap argumen dalam panggilan fungsi, dan Anda dapat menentukan apakah ada kelebihan beban yang tidak ambigu. Ini berarti bahwa ambiguitas dapat tetap berada dalam kode Anda sampai terpaksa oleh panggilan fungsi tertentu.
Perbedaan Tipe Argumen
Fungsi berlebih membedakan antara jenis argumen yang mengambil inisialisasi yang berbeda. Oleh karena itu, argumen dari jenis tertentu dan referensi ke jenis tersebut dianggap sama untuk tujuan kelebihan beban. Mereka dianggap sama karena mereka mengambil inisialisasi yang sama. Misalnya, max( double, double )
dianggap sama dengan max( double &, double & )
. Mendeklarasikan dua fungsi tersebut menyebabkan kesalahan.
Untuk alasan yang sama, argumen fungsi dari jenis yang dimodifikasi oleh const
atau volatile
tidak diperlakukan secara berbeda dari jenis dasar untuk tujuan kelebihan beban.
Namun, mekanisme kelebihan beban fungsi dapat membedakan antara referensi yang memenuhi syarat oleh const
dan volatile
dan referensi ke jenis dasar. Ini membuat kode seperti berikut mungkin:
// argument_type_differences.cpp
// compile with: /EHsc /W3
// C4521 expected
#include <iostream>
using namespace std;
class Over {
public:
Over() { cout << "Over default constructor\n"; }
Over( Over &o ) { cout << "Over&\n"; }
Over( const Over &co ) { cout << "const Over&\n"; }
Over( volatile Over &vo ) { cout << "volatile Over&\n"; }
};
int main() {
Over o1; // Calls default constructor.
Over o2( o1 ); // Calls Over( Over& ).
const Over o3; // Calls default constructor.
Over o4( o3 ); // Calls Over( const Over& ).
volatile Over o5; // Calls default constructor.
Over o6( o5 ); // Calls Over( volatile Over& ).
}
Output
Over default constructor
Over&
Over default constructor
const Over&
Over default constructor
volatile Over&
Penunjuk ke const
dan volatile
objek juga dianggap berbeda dari penunjuk ke jenis dasar untuk tujuan kelebihan beban.
Pencocokan argumen dan konversi
Ketika kompilator mencoba mencocokkan argumen aktual dengan argumen dalam deklarasi fungsi, kompilator dapat menyediakan konversi standar atau yang ditentukan pengguna untuk mendapatkan jenis yang benar jika tidak ada kecocokan yang tepat yang dapat ditemukan. Penerapan konversi tunduk pada aturan ini:
Urutan konversi yang berisi lebih dari satu konversi yang ditentukan pengguna tidak dipertimbangkan.
Urutan konversi yang dapat dipersingkat dengan menghapus konversi menengah tidak dipertimbangkan.
Urutan konversi yang dihasilkan, jika ada, disebut urutan pencocokan terbaik. Ada beberapa cara untuk mengonversi objek jenis int
ke jenis unsigned long
menggunakan konversi standar (dijelaskan dalam konversi Standar):
Konversi dari
int
kelong
dan kemudian darilong
keunsigned long
.Konversi dari
int
keunsigned long
.
Meskipun urutan pertama mencapai tujuan yang diinginkan, itu bukan urutan pencocokan terbaik, karena urutan yang lebih pendek ada.
Tabel berikut menunjukkan sekelompok konversi yang disebut konversi sepele. Konversi sepele memiliki efek terbatas pada urutan yang dipilih kompilator sebagai kecocokan terbaik. Efek konversi sepele dijelaskan setelah tabel.
Konversi sepele
Jenis Argumen | Jenis yang dikonversi |
---|---|
type-name |
type-name& |
type-name& |
type-name |
type-name[] |
type-name* |
type-name(argument-list) |
(*type-name)(argument-list) |
type-name |
const type-name |
type-name |
volatile type-name |
type-name* |
const type-name* |
type-name* |
volatile type-name* |
Urutan di mana konversi dicoba adalah sebagai berikut:
Kecocokan persis. Kecocokan yang tepat antara jenis yang fungsinya dipanggil dan jenis yang dideklarasikan dalam prototipe fungsi selalu merupakan kecocokan terbaik. Urutan konversi sepele diklasifikasikan sebagai kecocokan yang tepat. Namun, urutan yang tidak membuat salah satu konversi ini dianggap lebih baik daripada urutan yang mengonversi:
Dari pointer, ke pointer ke
const
(type-name*
keconst type-name*
).Dari pointer, ke pointer ke
volatile
(type-name*
kevolatile type-name*
).Dari referensi, hingga referensi ke
const
(type-name&
keconst type-name&
).Dari referensi, hingga referensi ke
volatile
(type-name&
kevolatile type&
).
Cocokkan menggunakan promosi. Urutan apa pun yang tidak diklasifikasikan sebagai kecocokan persis yang hanya berisi promosi integral, konversi dari
float
kedouble
, dan konversi sepele diklasifikasikan sebagai kecocokan menggunakan promosi. Meskipun tidak sebagus kecocokan yang sama persis, kecocokan menggunakan promosi lebih baik daripada kecocokan menggunakan konversi standar.Cocokkan menggunakan konversi standar. Urutan apa pun yang tidak diklasifikasikan sebagai kecocokan yang tepat atau kecocokan menggunakan promosi yang hanya berisi konversi standar dan konversi sepele diklasifikasikan sebagai kecocokan menggunakan konversi standar. Dalam kategori ini, aturan berikut diterapkan:
Konversi dari pointer ke kelas turunan, ke pointer ke kelas dasar langsung atau tidak langsung lebih disukai untuk mengonversi ke
void *
atauconst void *
.Konversi dari pointer ke kelas turunan, ke pointer ke kelas dasar menghasilkan kecocokan yang lebih baik semakin dekat kelas dasar dengan kelas dasar langsung. Misalkan hierarki kelas seperti yang ditunjukkan pada gambar berikut:
Grafik memperlihatkan konversi pilihan.
Konversi dari jenis D*
ke jenis C*
lebih disukai untuk konversi dari jenis D*
ke jenis B*
. Demikian pula, konversi dari jenis D*
ke jenis B*
lebih disukai untuk konversi dari jenis D*
ke jenis A*
.
Aturan yang sama ini berlaku untuk konversi referensi. Konversi dari jenis D&
ke jenis C&
lebih disukai untuk konversi dari jenis D&
ke jenis B&
, dan sebagainya.
Aturan yang sama ini berlaku untuk konversi pointer-to-member. Konversi dari jenis T D::*
ke jenis T C::*
lebih disukai untuk konversi dari jenis ke jenis T D::*
T B::*
, dan sebagainya (di mana T
adalah jenis anggota).
Aturan sebelumnya hanya berlaku di sepanjang jalur derivasi tertentu. Pertimbangkan grafik yang diperlihatkan dalam gambar berikut.
Grafik beberapa pewarisan yang menunjukkan konversi pilihan.
Konversi dari jenis C*
ke jenis B*
lebih disukai untuk konversi dari jenis C*
ke jenis A*
. Alasannya adalah bahwa mereka berada di jalur yang sama, dan B*
lebih dekat. Namun, konversi dari jenis C*
ke jenis D*
tidak lebih disukai untuk konversi ke jenis A*
; tidak ada preferensi karena konversi mengikuti jalur yang berbeda.
Cocokkan dengan konversi yang ditentukan pengguna. Urutan ini tidak dapat diklasifikasikan sebagai kecocokan yang tepat, kecocokan menggunakan promosi, atau kecocokan menggunakan konversi standar. Untuk diklasifikasikan sebagai kecocokan dengan konversi yang ditentukan pengguna, urutan hanya boleh berisi konversi yang ditentukan pengguna, konversi standar, atau konversi sepele. Kecocokan dengan konversi yang ditentukan pengguna dianggap cocok dengan yang lebih baik daripada kecocokan dengan elipsis (
...
) tetapi tidak cocok dengan kecocokan dengan konversi standar.Cocokkan dengan elipsis. Urutan apa pun yang cocok dengan elipsis dalam deklarasi diklasifikasikan sebagai kecocokan dengan elipsis. Ini dianggap sebagai pertandingan terlemah.
Konversi yang ditentukan pengguna diterapkan jika tidak ada promosi atau konversi bawaan. Konversi ini dipilih berdasarkan jenis argumen yang dicocokkan. Pertimbangkan gambar berikut:
// argument_matching1.cpp
class UDC
{
public:
operator int()
{
return 0;
}
operator long();
};
void Print( int i )
{
};
UDC udc;
int main()
{
Print( udc );
}
Konversi yang ditentukan pengguna yang tersedia untuk kelas UDC
berasal dari jenis int
dan jenis long
. Oleh karena itu, pengkompilasi mempertimbangkan konversi untuk jenis objek yang cocok: UDC
. Konversi ke int
ada, dan dipilih.
Selama proses pencocokan argumen, konversi standar dapat diterapkan ke argumen dan hasil konversi yang ditentukan pengguna. Oleh karena itu, kode berikut berfungsi:
void LogToFile( long l );
...
UDC udc;
LogToFile( udc );
Dalam contoh ini, pengkompilasi memanggil konversi yang ditentukan pengguna, , operator long
untuk mengonversi udc
ke jenis long
. Jika tidak ada konversi yang ditentukan pengguna ke jenis long
yang ditentukan, pengkompilasi akan terlebih dahulu mengonversi jenis UDC
untuk mengetik int
menggunakan konversi yang ditentukan operator int
pengguna. Kemudian akan menerapkan konversi standar dari jenis ke jenis int
long
untuk mencocokkan argumen dalam deklarasi.
Jika ada konversi yang ditentukan pengguna yang diperlukan untuk mencocokkan argumen, konversi standar tidak digunakan saat mengevaluasi kecocokan terbaik. Bahkan jika lebih dari satu fungsi kandidat memerlukan konversi yang ditentukan pengguna, fungsi dianggap sama. Contohnya:
// argument_matching2.cpp
// C2668 expected
class UDC1
{
public:
UDC1( int ); // User-defined conversion from int.
};
class UDC2
{
public:
UDC2( long ); // User-defined conversion from long.
};
void Func( UDC1 );
void Func( UDC2 );
int main()
{
Func( 1 );
}
Kedua versi Func
memerlukan konversi yang ditentukan pengguna untuk mengonversi jenis int
ke argumen jenis kelas. Konversi yang mungkin adalah:
Konversi dari jenis
int
ke jenisUDC1
(konversi yang ditentukan pengguna).Konversi dari jenis ke jenis
int
long
; lalu konversi ke jenisUDC2
(konversi dua langkah).
Meskipun yang kedua memerlukan konversi standar dan konversi yang ditentukan pengguna, kedua konversi masih dianggap sama.
Catatan
Konversi yang ditentukan pengguna dianggap sebagai konversi berdasarkan konstruksi atau konversi dengan inisialisasi. Pengkompilasi menganggap kedua metode sama ketika menentukan kecocokan terbaik.
Pencocokan argumen dan penunjuk this
Fungsi anggota kelas diperlakukan secara berbeda, tergantung pada apakah fungsi tersebut dinyatakan sebagai static
. static
fungsi tidak memiliki argumen implisit this
yang memasok pointer, sehingga dianggap memiliki satu argumen yang kurang dari fungsi anggota reguler. Jika tidak, mereka dinyatakan identik.
Fungsi anggota yang tidak memerlukan penunjuk static
tersirat untuk mencocokkan this
jenis objek yang dipanggil fungsi. Atau, untuk operator yang kelebihan beban, mereka memerlukan argumen pertama untuk mencocokkan objek yang diterapkan operator. Untuk informasi selengkapnya tentang operator yang kelebihan beban, lihat Operator kelebihan beban.
Tidak seperti argumen lain dalam fungsi yang kelebihan beban, pengompilasi tidak memperkenalkan objek sementara dan tidak mencoba konversi saat mencoba mencocokkan this
argumen pointer.
->
Ketika operator pemilihan anggota digunakan untuk mengakses fungsi anggota kelas class_name
, this
argumen pointer memiliki jenis class_name * const
. Jika anggota dinyatakan sebagai const
atau volatile
, jenisnya adalah const class_name * const
dan volatile class_name * const
, masing-masing.
Operator .
pemilihan anggota bekerja dengan cara yang sama persis, kecuali bahwa operator implisit &
(address-of) diawali dengan nama objek. Contoh berikut menunjukkan cara kerjanya:
// Expression encountered in code
obj.name
// How the compiler treats it
(&obj)->name
Operan ->*
kiri operator dan .*
(penunjuk ke anggota) diperlakukan dengan cara yang sama seperti .
operator dan ->
(pemilihan anggota) sehubungan dengan pencocokan argumen.
Kualifikasi referensi pada fungsi anggota
Kualifikasi referensi memungkinkan untuk membebani fungsi anggota berdasarkan apakah objek yang diacu oleh this
adalah rvalue atau lvalue. Gunakan fitur ini untuk menghindari operasi penyalinan yang tidak perlu dalam skenario di mana Anda memilih untuk tidak menyediakan akses penunjuk ke data. Misalnya, asumsikan kelas C
menginisialisasi beberapa data dalam konstruktornya, dan mengembalikan salinan data tersebut dalam fungsi get_data()
anggota . Jika objek jenis C
adalah rvalue yang akan dihancurkan, pengkompilasi memilih get_data() &&
kelebihan beban, yang bergerak alih-alih menyalin data.
#include <iostream>
#include <vector>
using namespace std;
class C
{
public:
C() {/*expensive initialization*/}
vector<unsigned> get_data() &
{
cout << "lvalue\n";
return _data;
}
vector<unsigned> get_data() &&
{
cout << "rvalue\n";
return std::move(_data);
}
private:
vector<unsigned> _data;
};
int main()
{
C c;
auto v = c.get_data(); // get a copy. prints "lvalue".
auto v2 = C().get_data(); // get the original. prints "rvalue"
return 0;
}
Pembatasan kelebihan beban
Beberapa pembatasan mengatur sekumpulan fungsi yang kelebihan beban yang dapat diterima:
Setiap dua fungsi dalam sekumpulan fungsi yang kelebihan beban harus memiliki daftar argumen yang berbeda.
Fungsi kelebihan beban yang memiliki daftar argumen dari jenis yang sama, berdasarkan jenis pengembalian saja, adalah kesalahan.
Khusus Microsoft
Anda dapat kelebihan beban
operator new
berdasarkan jenis pengembalian, khususnya, berdasarkan pengubah model memori yang ditentukan.END Khusus Microsoft
Fungsi anggota tidak dapat kelebihan beban hanya karena satu adalah
static
dan yang lain bukanstatic
.typedef
deklarasi tidak menentukan jenis baru; mereka memperkenalkan sinonim untuk jenis yang ada. Mereka tidak memengaruhi mekanisme kelebihan beban. Pertimbangkan gambar berikut:typedef char * PSTR; void Print( char *szToPrint ); void Print( PSTR szToPrint );
Dua fungsi sebelumnya memiliki daftar argumen yang identik.
PSTR
adalah sinonim untuk jenischar *
. Dalam cakupan anggota, kode ini menghasilkan kesalahan.Jenis enumerasi adalah jenis yang berbeda dan dapat digunakan untuk membedakan antara fungsi yang kelebihan beban.
Jenis "array of" dan "pointer to" dianggap identik untuk tujuan membedakan antara fungsi yang kelebihan beban, tetapi hanya untuk array satu dimensi. Fungsi yang kelebihan beban ini berkonflik dan menghasilkan pesan kesalahan:
void Print( char *szToPrint ); void Print( char szToPrint[] );
Untuk array dimensi yang lebih tinggi, dimensi kedua dan yang lebih baru dianggap sebagai bagian dari jenis. Fungsi ini digunakan untuk membedakan antara fungsi yang kelebihan beban:
void Print( char szToPrint[] ); void Print( char szToPrint[][7] ); void Print( char szToPrint[][9][42] );
Kelebihan beban, pengesampingan, dan persembunyian
Setiap dua deklarasi fungsi dengan nama yang sama dalam cakupan yang sama dapat merujuk ke fungsi yang sama, atau ke dua fungsi diskrit yang kelebihan beban. Jika daftar argumen deklarasi berisi argumen jenis yang setara (seperti yang dijelaskan di bagian sebelumnya), deklarasi fungsi merujuk ke fungsi yang sama. Jika tidak, mereka merujuk ke dua fungsi berbeda yang dipilih menggunakan kelebihan beban.
Cakupan kelas diamati secara ketat. Fungsi yang dideklarasikan dalam kelas dasar tidak berada dalam cakupan yang sama dengan fungsi yang dideklarasikan dalam kelas turunan. Jika fungsi dalam kelas turunan dinyatakan dengan nama virtual
yang sama dengan fungsi di kelas dasar, fungsi kelas turunan mengambil alih fungsi kelas dasar. Untuk informasi selengkapnya, lihat Fungsi Virtual.
Jika fungsi kelas dasar tidak dinyatakan sebagai virtual
, maka fungsi kelas turunan dikatakan menyembunyikannya. Pengesampingan dan persembunyian berbeda dari kelebihan beban.
Cakupan blok diamati secara ketat. Fungsi yang dideklarasikan dalam cakupan file tidak berada dalam cakupan yang sama dengan fungsi yang dideklarasikan secara lokal. Jika fungsi yang dideklarasikan secara lokal memiliki nama yang sama dengan fungsi yang dideklarasikan dalam cakupan file, fungsi yang dideklarasikan secara lokal menyembunyikan fungsi cakupan file alih-alih menyebabkan kelebihan beban. Contohnya:
// declaration_matching1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void func( int i )
{
cout << "Called file-scoped func : " << i << endl;
}
void func( char *sz )
{
cout << "Called locally declared func : " << sz << endl;
}
int main()
{
// Declare func local to main.
extern void func( char *sz );
func( 3 ); // C2664 Error. func( int ) is hidden.
func( "s" );
}
Kode sebelumnya menunjukkan dua definisi dari fungsi func
. Definisi yang mengambil argumen jenis char *
bersifat lokal main
karena extern
pernyataan . Oleh karena itu, definisi yang mengambil argumen jenis int
disembunyikan, dan panggilan pertama ke func
dalam kesalahan.
Untuk fungsi anggota yang kelebihan beban, versi fungsi yang berbeda dapat diberikan hak istimewa akses yang berbeda. Mereka masih dianggap berada dalam cakupan kelas penutup dan dengan demikian merupakan fungsi yang kelebihan beban. Pertimbangkan kode berikut, di mana fungsi Deposit
anggota kelebihan beban; satu versi bersifat publik, yang lain, privat.
Tujuan dari sampel ini adalah untuk memberikan Account
kelas di mana kata sandi yang benar diperlukan untuk melakukan setoran. Ini dilakukan dengan menggunakan kelebihan beban.
Panggilan ke Deposit
dalam Account::Deposit
memanggil fungsi anggota privat. Panggilan ini benar karena Account::Deposit
merupakan fungsi anggota, dan memiliki akses ke anggota privat kelas.
// declaration_matching2.cpp
class Account
{
public:
Account()
{
}
double Deposit( double dAmount, char *szPassword );
private:
double Deposit( double dAmount )
{
return 0.0;
}
int Validate( char *szPassword )
{
return 0;
}
};
int main()
{
// Allocate a new object of type Account.
Account *pAcct = new Account;
// Deposit $57.22. Error: calls a private function.
// pAcct->Deposit( 57.22 );
// Deposit $57.22 and supply a password. OK: calls a
// public function.
pAcct->Deposit( 52.77, "pswd" );
}
double Account::Deposit( double dAmount, char *szPassword )
{
if ( Validate( szPassword ) )
return Deposit( dAmount );
else
return 0.0;
}