49835


`heaedr.h`部の複数コメント部の`C& operator = (const D& x);`を定義して `int main()`で`基底 =
派生;`の挙動を変えてみよう思うい、そのコードを書いてみたのですが[xが定義されていない識別子です]や[構文エラー: ',' が '&'
の前にありません]などといった意味のわからないコンパイルエラーが出るのですが原因がわからず困っています。  
１、エラーの原因と対処法を知りたい。  
２、初学者のためそもそもこの行為が正しい行為なのかもわかりらずもっといい書き方がのならばそのあたりも教えてほしいです。  
3,そもそもこれはやっていいのか？

[code]

    ////////////Header.h部///////////////////////////////////
    
    #pragma once
    #ifndef ___Header_h
    #define ___Header_h
    #include <iostream>
    #include <String>
    using namespace std;
    
    
    class C {
    private:
    protected:
    
            string name;
    
    public:
    
            C(string n = "no name"):name(n)
            {
                    cout << "基底コンストラクタ\n";
            }
    
            string g_str()const
            {
                    return name;
            }
    
    
    
    
            C& operator = (const C& x)
            {
                    if (this != &x)
                    {
                            cout << "クラスC　代入 C& operator = (const C& x)\n";
                            name = x.name;
                    }
    
                    return *this;
            }
    
    
            //C& operator = (const D& x)
            //{
            //      if (this != &x)
            //      {
            //              cout << "クラスC　代入 C& operator = (const C& x)\n";
            //              name = x.dg_name();
            //      }
    
            //      return *this;
            //}
    
    
            C(const C& x)
            {
                    cout << "クラスC　コピー C(const C& x)\n";
                    if (this != &x)
                    {
                            name = x.name;
                    }
            }
    
            void print() { cout << "class C\n"; }
    
            virtual void view()const {
                    cout << " 基底クラス　name : " << name << "\n";
    
            }
    
    
    };
    
    class D : public C {
    private:
            string name;
    protected:
    public:
    
            virtual void view()const
            {
                    cout << " 派生クラス name: " << name <<"\n";
                    cout << " 基底クラス name: " << C::name << "\n";
            }
    
            string dg_name()const
            {
                    return name;
            }
    
            D& operator = (const D& x)
            {
                    cout << "クラスD　代入 D& operator = (const D& x)\n";
                    if (this != &x)
                    {
                            name = x.name;
                    }
    
                    return *this;
            }
    
            D& operator = (const C& x)
            {
                    if (this != &x)
                    {
                            cout << "クラスD　代入 D& operator = (const C& x)\n";
    
                            C::name = x.g_str();
                    }
    
                    return *this;
            }
    
            D(const D& x)
            {
    
                    if (this != &x)
                    {
                            cout << "派生クラスのコピー\n";
                            name = x.name;
                    }
            }
    
            void print() { cout << "class D\n"; }
    
            D(string n = "no name",string nn = "no name"):C(nn),name(n)
            {
                    cout << "派生コンストラクタ\n";
            }
    
    
    };
    
    
    
    #endif
    
    ///////int main()//////////////////// 
    
    #include <iostream>
    #include "conio.h"
    #include "Header.h"
    using namespace std;
    
    
    int main()
    {
            C a("test a");
            C b("test b");
            D d1("d1 test","dd1 test");//派生、基底
            D d2("d2 test", "dd2 test");
    
    
            a = d1;//
    
    
            _getch();
            return 0;
    }
    
[/code]


CC BY-SA 4.0
2018-10-31T14:40:09.353
49832
2018-11-01T05:15:11.427
2018-11-01T05:15:11.427
5008
question
c++
c++, operator関数でエラーになる。原因が知りたい


オイラ一読して疑問点がどこかよくわからなかったんだけど、再読してみて

Q1: 提示コード中ではコメント化している箇所 `C::operator=` を、コメント外してコンパイルするとエラーになるが、どうすればよいか？

ってことであるとして以下回答。  
[c++,フレンドクラスの使おうとすると認識できない型です、というエラー出る。原因](https://ja.stackoverflow.com/questions/48815/)  
で「コメント」した通りっす。

`class D` は結局のところ `C` から派生させている `class D : public C` ので、この派生クラス `D` のクラス定義は
`class C` のクラス定義が完全になるまでできません。

[code]

    class C { ... }; // の波括弧が閉じた後でないと
    class D : public C { ... }; // のように C を使うことはできない
    
[/code]

当然ながら `class C { ... };` の最中にはまだ `D` は存在していないので「定義されていない識別子」のエラーが出ます。なので `D`
という名前はクラス名だよ、とコンパイラに教える「クラス宣言」を先行させることで「メンバ関数宣言」はできるようになります。「クラス宣言」だけだと詳細がないので「メンバ関数の定義」はこの時点ではまだできません。

[code]

    // myclass.h
    class D;
    class C { ...
        C& operator=(const D& d); // メンバ関数宣言のみなら可能
    };
    
[/code]

`class D` のクラス定義が完全になった後であれば `D`
を使うことができるので「関数定義」を書くことができます。ヘッダファイル中でこの関数定義を行うと ODR に反するので `myclass.cpp`
を新しく作ってその中で行う必要があります。

[code]

    // myclass.cpp
    #include "myclass.h"
    C& C::operator=(const D& d) { ... }
    
[/code]

っていうか多分下記の解説を先にしとくべきなのかもしれない。

  * 宣言 (declaration)  
そういう名前の変数や関数やクラスがあることをコンパイラに知らせる行為  
宣言だけを行う場合、その名前を「使う」ことができる状況は限られてしまう

  * 定義 (definition)  
変数や関数やクラスの詳細をコンパイラに知らせる行為  
多くの場合、定義は同時に宣言を兼ねるが「定義にならない宣言」もある  
定義が完了しないと、その名前を「使う」ことができない

`class D;` ってのは「定義にならない宣言」で、これだけあるときコンパイラは  
\- `D` ってのはクラス名であるが、その詳細は不明  
\- `D*` および `D&` と書いてあるコードは容認する  
\- `extern D d;` のような「変数宣言（変数定義にならない宣言）」を容認する  
\- `D` 自体を使うことはできない（ `D` の詳細が不明なため）

A1: この場合は、クラス定義内関数宣言と関数定義を分離する必要があります。関数宣言はヘッダファイルで、関数定義はソースファイルで実施のこと。

Q2-1:クラス宣言だけ先行させる使い方は普通？正しい？  
A2-1:普通かつ正しい行為です。関数宣言と関数定義を別に書く必要があるので１手間余計にかかりますが、オイラも何度もやったことあります。

Q2-2:基底クラスオブジェクトに、派生オブジェクトを代入する行為は普通？正しい？  
A2-2:オイラの経験上はそういう行為をする必然があったことが一度もないので、普通かと問われれば否。正しいかと問われれば「基底クラスが派生クラスについて事前に知っておく必要がある」ってのはまったくもって正しくない。

Q3:やっていいの？  
A3:実験目的、学習目的なら可。オイラの後輩君が実用に供するコードにこんなこと書いてたらリファクタリングを強制するだろう。


CC BY-SA 4.0
2018-11-01T00:38:44.053
49835
2018-11-01T00:38:44.053
8589
49832
answer