Bagikan melalui


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 Tidak
Jumlah argumen Ya
Jenis argumen Ya
Kehadiran atau tidak adanya elipsis Ya
Penggunaan typedef nama Tidak
Batas array yang tidak ditentukan Tidak
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 2dan 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& ).
}

Hasil

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 ke long dan kemudian dari long ke unsigned long.

  • Konversi dari int ke unsigned 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:

  1. 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* ke const type-name*).

    • Dari pointer, ke pointer ke volatile (type-name* ke volatile type-name*).

    • Dari referensi, hingga referensi ke const (type-name& ke const type-name&).

    • Dari referensi, hingga referensi ke volatile (type-name& ke volatile type&).

  2. Cocokkan menggunakan promosi. Urutan apa pun yang tidak diklasifikasikan sebagai kecocokan persis yang hanya berisi promosi integral, konversi dari float ke double, 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.

  3. 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 * atau const 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:

Example class hierarchy showing that class A inherits from B which inherits from C which inherits from D.
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.

Diagram of multiple inheritance that shows preferred conversions. Class C is the base class of class B and D. Class A inherits from class B
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.

  1. 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.

  2. 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 longuntuk 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 intlong 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 jenis UDC1 (konversi yang ditentukan pengguna).

  • Konversi dari jenis ke jenis intlong; lalu konversi ke jenis UDC2 (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 bukan static.

  • 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 jenis char *. 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;
}

Baca juga

Functions (C++)