コンパイラは、名前マングリングと呼ばれる手法を使用します。
簡単に言えば、コンパイラは引数の数と型を、オブジェクト ファイルに書き込まれる実際の名前にエンコードします。このテーマに関するウィキペディアの記事には、C++ の例を含むいくつかの例があります。
具体的な例として、Mac で g++ を使用して次の C++ ファイルをコンパイルしました。
test.cpp
int f(int x) {}
int f(double x, char y) {}
と
g++ -S test.cpp
これにより、アセンブリ言語ファイルが生成されます (多少省略されています)。
test.s
.globl __Z1fi
__Z1fi:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
leave
ret
.globl __Z1fdc
__Z1fdc:
pushq %rbp
movq %rsp, %rbp
movsd %xmm0, -8(%rbp)
movb %dil, -12(%rbp)
leave
ret
ここで重要な点は、関数が呼び出さ__Z1fi
れ__Z1fdc
、アセンブリ言語の出力で、リンカが確認できることです。f
おそらくそれが関数の名前であると推測できます。引数には、 i
(int) とdc
(double と char) があります。引数の順序もエンコードされることに注意してください!
もしあなたが持っていたらどうなるか考えてみてください
int f(int x) {}
int f(int y) {}
これはもちろん、言語に関する限り、容認できる状況ではありf(10)
ません。理論的には、言語は 2 番目の宣言が最初の宣言を置き換えることを指定できますが、C++ はこれを行いません。これは単に違法なオーバーロードです。
名前マングリングは、これがエラーになる理由を実際に示していることがわかりました。コンパイラは、名前を持つ 2 つの異なる関数を作成しようとします__Z1fi
(実際の名前は言語によって定義されていませんが、コンパイラに依存します)。このレベルのプログラムでは、同じ名前の関数を 2 つ持つことはできません。