6

ディスプレイに渡された引数が同じタイプであるため、次のコードがエラーを生成しない理由がわかりません。つまりcharconst本当に違いがありますか?

#include<iostream>

using namespace std;

void display(char *p)
{
    cout<<p;
}
void display(const char *p)
{
    cout<<p;
}

int main()
{
    display("Hello");
    display("World");
}

編集 回答によると、最初のディスプレイは呼び出されません。これは正しく、出力もそうです。

しかし、私はそれを次のようにするとします:

int main()
{
    char *p="Hello";
    display(p);//now first display is called.
    display("World");
}

コンパイラは a をwarning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]返しますが、最初の表示を呼び出します。これは、文字列が定数として扱われなくなったことを意味しますか?

4

6 に答える 6

11

const char*char *実際には同じではありません。後者は指摘された を変更できますがchar、最初のものはそれを防ぎます。

また、それらがクラス メソッドである場合void display()void display() const有効なオーバーロードでもあることに注意してください。後者は、メソッドがオブジェクトの状態を変更してはならないことを意味します。

次のコードを検討してください。

void    display(char *s)
{
  std::cout << "Display" << std::endl;
}

void    display(const char *s)
{
  std::cout << "Display with const" << std::endl;
}

int     main()
{
  char  *str = strdup("boap");
  const char *str2 = "toto";
  /* It is a string literral "bound" as a char *.                                                                               
     Compiler will issue warning, but it still compiles.                                                                        
     Avoid to do that, it's just an exemple */
  char  *not_safe = "not_safe";

  display("llama");
  display(str2);
  display(str);
  display(not_safe);
}

これはDisplay with const2 回出力され、次に 2 回出力されDisplayます。そこを参照してください。では、その理由を見てみましょう。

  • "llama"は文字列リテラルであり、 として解決されますconst char *
  • str2文字列リテラルへのポインタです。その型はであるためconst char*、これもconstオーバーロードに関係します。
  • not_safe文字列リテラルへのポインタでもあります。ただし、そのタイプはchar *:これは正しくありません。それが指すメモリは読み取り専用であり、変更しようとするとクラッシュします。ただし、変数の型はまだなchar *ので、これは非constオーバーロードに解決されます。
  • strchar *ポインタであり、それが指す文字列は読み取り専用ではありません。その内容の変更は有効であり、その型はchar *であるため、非 const オーバーロードに解決されます。
于 2013-07-26T07:29:02.323 に答える
3

"Hello"問題は、やなどの文字列リテラル"World"に type があることconst char[6]です。これは まで減衰できますが、 までは減衰しconst char*ませんchar*。したがって、オーバーロードを取るconst char*と、

 void display(const char *p);

より良い一致です。@JamesKanze が指摘しているように、関数がchar*文字列リテラルを受け入れることは可能ですが、ポイントされたデータを変更しようとすると、未定義の動作が発生します。このため、そのような関数に文字列リテラルを渡すのは安全ではありません。適切な警告設定により、GCC は以下を生成します。

警告: 文字列定数から 'char*' への非推奨の変換</p>

いずれにせよ、あなたが示したような 2 つのオーバーロードが存在する場合は、取った方がconst char*勝ちます。

于 2013-07-26T07:36:30.053 に答える
0

2 つの関数に渡される引数は、実際には同じではありません。

最初のものは、次のものを取りますchar*: a へのポインターchar

2 番目の引数は次のconst char*とおりです。 a へのポインターconst char

ご覧のとおり、ここでの違いは実際には、ポインターが変更可能なオブジェクトを指しているかどうかにあります。これは間違いなく、関数をオーバーロードできるようにしたいプロパティです。

于 2013-07-26T07:25:37.443 に答える
0

文字列 "Hello" と "World" のサイズはコンパイル時に認識され、変更できません。これらは定数のコンパイル時の文字配列です。

C および C++ では、配列 egchar a[6]はポインターを使用して参照できます。つまりa、実際にはchar *です。「Hello」と「World」の配列は実行時に変更してはならないため、それらの型は基本的にconst char *です。

display関数 ( display(const char* p)) の 1 つだけが引数として a を取るため、コンパイラはこれを認識し、オーバーロードの解決を正しく実行しconst char*ます。これが、2 つの関数にあいまいさがなく、予期したエラーが発生しない理由です。

于 2013-07-26T07:33:24.610 に答える
0

オブジェクトを変更できるかどうかは、さまざまな動作を呼び出したい場合に応じて、役立つ情報です。このことを考慮:

void foo(int * p) { ++(*p); }
void foo(int const * p) { std::cout << *p << '\n'; }
于 2013-07-26T07:29:52.553 に答える
0

「表示に渡された引数が同じ型、つまり char であるためです。」

いいえ、引数は「const char*」です。データ型はですが、const 修飾子は、ハードコーディングしたリテラル文字列が変更できるものではないことを示しています。

「constは本当に違いますか?」

はい、const修飾子が違いを生みます。Display(char*) では、渡したヌル終了文字列の内容を更新できますが、Display(const char*) では更新できません。その事実により、コンパイラによるより多くの最適化が可能になります。

しかし、 http://www.possibility.com/Cpp/const.htmlを読んでください。 const を効率的に使い始めるための良い情報源です。

于 2013-07-26T07:35:20.120 に答える