質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

1277閲覧

自作STLクラスのイテレータが正しく動作しません

do_Shiro_to

総合スコア15

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2020/03/08 05:49

編集2020/03/08 22:17

前提・実現したいこと

課題で提示されたコードを元に、vectorとlist用の簡易イテレータを自作しているのですが、コンパイルしようとすると大量のエラーメッセージがでてしまいます。よく調べてみると、どうやらiteratorクラスがvector, listのメンバーではない故にエラーが起こっているようですが、ちゃんと親クラス?内にiteratorクラスを作っているのでなんでこうなるのかわかりません…どう解決すればいいのでしょうか…

このエラーばかり出てコンパイルできないので、肝心のiterator内の関数の挙動が確認できず、正しくかけているのかわかりません。もしよろしければ、iteratorクラスが正しく書けているかチェックして、間違えている所などあれば指摘や助言などしてくださるとありがたいです。

main.cppを改変することは許可されていないので、
mainをいじらない解決方法を教えてくださると助かります。

発生している問題・エラーメッセージ

E0135 class "Vector<int>" has no member "Iterator"などなど百件以上…

該当のソースコード

C++

1template<typename T> 2class Vector 3{ 4 T* mData; 5 int mSize; 6 int mCapacity; 7 8 static T sUndefined; 9public: 10 11 12 Vector()// O(1) 13 { 14 mSize = 0; 15 mCapacity = 15; 16 mData = new T[mCapacity]; 17 } 18 Vector(const Vector<T>& tOther) : Vector(); // O(n) 19 20 Vector& operator =(const Vector<T>& tRHS); // O(n) 21 22 ~Vector(); 23 24 void PushBack(const T& tItem); // O(1) 25 26 void PopBack();// O(1) 27 28 void PushFront(const T& tItem);// O(n) 29 30 void PopFront(); // O(n) 31 32 T& At(int tWhere) const; // O(1) 33 34 void Clear(); // O(1) 35 36 int Size() const; // O(1) 37 38 void Reserve(int tCount); // O(n) 39 40 int Capacity() const; // O(1) 41 42 43 class Iterator 44 { 45 int mCurrentIndex = 0; 46 Vector<T> *mMyVector = nullptr;     47 friend class Vector<T>; 48 49 Iterator(Vector<T> *tWho, int tLocation) 50 { 51 mMyVector = tWho; 52 mCurrentIndex = tLocation; 53 } 54 public: 55 T& GetData() 56 { 57 if (mMyVector[mCurrentIndex] != nullptr) 58 { 59 return mMyVector[mCurrentIndex]; 60 } 61 return sUndefined; 62 } 63 void Next() 64 { 65 mCurrentIndex += 1; 66 } 67 bool IsEqual(const Iterator& rhs) 68 { 69 int tCount = 0; 70 mCurrentIndex = 0; 71 int tSize = mMyVector->Size(); 72 73 while (tSize != mCurrentIndex-1) 74 { 75 if (mMyVector[mCurrentIndex] == rhs.GetData) 76 { 77 tCount++; 78 } 79 mCurrentIndex++; 80 } 81 82 if (tCount == tSize) 83 { 84 return true; 85 } 86 else 87 { 88 return false; 89 } 90 } 91 }; 92 93 Iterator Insert(Iterator tWhere, const T& tWhat) 94 { 95 if (mSize == mCapacity) 96 Reserve(2 * mCapacity); 97 98 int tSize = 0; 99 int tRet = 0; 100 T* tData = new T[mCapacity]; 101 102 for (int i = 0; i < mSize; i++) 103 { 104 if(mData[i] == tWhere) 105 { 106 tData[tSize] = tWhat; 107 tSize++; 108 tRet = i + 1; 109 } 110 tData[tSize] = mData[i]; 111 ++tSize; 112 } 113 114 delete[] mData; 115 mData = tData; 116 mSize = tSize; 117 118 Iterator tAnswer(mData, tRet); 119 return tAnswer; 120 } 121 Iterator Erase(Iterator tWhere) 122 { 123 int tSize = 0; 124 int tRet = 0; 125 T* tData = new T[mCapacity]; 126 127 for (int i = 0; i < mSize; i++) 128 { 129 if (mData[i] == tWhere) 130 { 131 ++tSize; 132 tData[i] = mData[tSize]; 133 tRet = i+1; 134 } 135 tData[i] = mData[tSize]; 136 ++tSize; 137 } 138 139 delete[] mData; 140 mData = tData; 141 mSize = i; 142 143 Iterator tAnswer(mData, tRet); 144 return tAnswer; 145 } 146 Iterator Begin() 147 { 148 Iterator tAnswer(mData, 0); 149 return tAnswer; 150 } 151 Iterator End() 152 { 153 Iterator tAnswer(mData, mSize); 154 return tAnswer; 155 } 156}; 157 158template<typename T> 159T Vector<T>::sUndefined;

C++

1template <typename T> 2class List 3{ 4 struct ListNode 5 { 6 ListNode() 7 { 8 mPrev = nullptr; 9 mNext = nullptr; 10 } 11 T mData; 12 ListNode* mPrev; 13 ListNode* mNext; 14 }; 15 16 ListNode* mHead; 17 ListNode* mTail; 18 19public: 20 List() 21 { 22 //mHead = nullptr;// Technically works, but we gain so much with sentinel nodes 23 //mTail = nullptr; 24 25 mHead = new ListNode;// You always know there is a node to the left and right 26 mTail = new ListNode; 27 mHead->mNext = mTail; 28 mTail->mPrev = mHead; 29 } 30 List(const List& tOther) : List(); 31 32 List& operator = (const List& tRHS); 33 34 ~List(); 35 36 void PushFront(const T& tWhat); 37 38 void PopFront(); 39 40 static T sUnspecifiedStaticVar; 41 42 T& Front(); 43 44 void PushBack(const T& tWhat); 45 46 void PopBack(); 47 48 T& Back(); 49 50 int Size(); 51 52 void Clear(); 53 54 T& At(int tWhere) const; 55 56 class Iterator 57 { 58 ListNode* mCurrent; 59 friend class List<T>; 60 Iterator(ListNode* tStart) 61 { 62 mCurrent = tStart; 63 } 64 public: 65 T& GetData() 66 { 67 return mCurrent->mData; 68 } 69 void Next() 70 { 71 mCurrent = mCurrent->mNext; 72 } 73 bool IsEqual(const Iterator& rhs) const 74 { 75 return mCurrent == rhs.mCurrent; 76 } 77 }; 78 79 Iterator Insert(Iterator tWhere, const T& tWhat) 80 { 81 ListNode* tNew = new ListNode; 82 tNew->mData = tWhat; 83 84 ListNode* tPrev = tWhere; 85 ListNode* tNext = tPrev->mNext; 86 tNext->mPrev = tPrev; 87 88 tPrev->mNext = tNew; 89 tNew->mPrev = tPrev; 90 tNew->mNext = tNext; 91 tNext->mPrev = tNew; 92 93 return Iterator(tNew->mNext); 94 } 95 Iterator Erase(Iterator tWhat) 96 { 97 ListNode* tDead = tWhat; 98 ListNode* tNext = tDead->mNext; 99 ListNode* tPrev = tDead->mPrev; 100 tPre->mNext = tDead; 101 tNext->mPrev = tDead; 102 delete tDead; 103 104 tPrev->mNext = tNext; 105 tNext->mPrev = tPrev; 106 107 return Iterator(tNext); 108 109 } 110 Iterator Begin() 111 { 112 return Iterator(mHead->mNext); 113 } 114 Iterator End() 115 { 116 return Iterator(mTail); 117 } 118};

VectorとListの関数を簡略しているので、このままコンパイルはできません。
こんな感じのmainで動かせればいいなと思います。

C++

1#include <iostream> 2#include "List.h" 3#include "Vector.h" 4 5using namespace std; 6 7int main() 8{ 9 Vector<int> tTester; 10 tTester.PushBack(0); 11 tTester.PushBack(1); 12 tTester.PushBack(2); 13 14 for (Vector<int>::Iterator iter = tTester.Begin(); !iter.IsEqual(tTester.End()); iter.Next()) 15 { 16 cout << iter.GetData() << " "; 17 } 18 19 cout << endl; 20 tTester.Erase(tTester.Begin()); 21 22 for (Vector<int>::Iterator iter = tTester.Begin(); !iter.IsEqual(tTester.End()); iter.Next()) 23 { 24 cout << iter.GetData() << " "; 25 } 26 27 cout << endl; 28 tTester.Insert(tTester.Begin(), 999); 29 tTester.Insert(tTester.Begin(), 888); 30 31 for (Vector<int>::Iterator iter = tTester.Begin(); !iter.IsEqual(tTester.End()); iter.Next()) 32 { 33 cout << iter.GetData() << " "; 34 } 35}

補足情報(FW/ツールのバージョンなど)

Visual Studio 2019 ver.16.0.2.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Chironian

2020/03/08 06:05

呼び出し側がないと超面倒ですので、呼び出し側も提示した方が回答が付きやすいですよ。
Chironian

2020/03/08 06:11

試しに、Vector<int> vec;を定義してみましたが、コンストラクタが適切に定義されていないため、エラーになります。Iteratorにまでたどり着かないです。まずは、Vectorをきちんと定義しましょう。
do_Shiro_to

2020/03/08 22:20

返答ありがとうございます。 お手数をおかけして申し訳ありません。あくまで雰囲気だけですが、呼び出し側も追加いたしました。 具体的に、Vectorのコンストラクタをどう定義をすればIteratorにたどり着くのでしょうか…?
Chironian

2020/03/09 03:58

それはまた別途質問された方が良いと思います。ただ内容的にC++の基本文法の話ですので「まるなげ」との低評価が付く可能性があります。ですので、まずはご自身でコンストラクタの書き方を調査されたほうが無用なストレスを回避できる可能性が高いです。 http://kaitei.net/cpp/constructors/
guest

回答2

0

全体的におかしいのでどこがおかしいということを指摘するのが難しいのですが、ちょっとした書き損じを別にして根本的に理解を間違えているらしいのは「クラス内でクラスを定義する意味」についてです。

クラスの中で定義するクラスというのは可視性を制御するに過ぎず、データに親子関係が出来るわけではありません。 Vector のメンバである mDataSize に対して具体的なオブジェクトを経由せずに Vector::Iterator のメンバ関数内からアクセスすることはできません。 逆に Vector::Iterator のメンバである mMyVectorVector のメンバ関数が使っているのも奇妙です。

Vector のイテレータを定義するために Vector 内で定義する必要はありません。 やりたければ Vector 内に Iterator を定義してもかまいませんが実際には無い関連性を見出してしまって混乱しているように見えるので分けて考え直した方が良いのではないかと思います。

投稿2020/03/08 06:26

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

do_Shiro_to

2020/03/08 22:37

ご返信ありがとうございます。 指摘をいただいたところをできるだけ直して、再アップさせていただきました。 クラス内クラス、いわゆるインナークラスというものを自分なりに調べてみたのですが、正直自分のコードとあまり違いが無いように見えました。クラス内にクラスを定義して、スコープ演算子を利用して、呼び出す。といった簡潔な感じで説明されていたのですが、なぜ自分のコードでは呼び出せないのでしょうか…?一応呼び出し側のコードも追加で載せたので、チェックしていただけると助かります。
SaitoAtsushi

2020/03/09 00:20

一気に良くなりました。 根本的な間違いと言える部分は改善されていると思います。 あとは細かな間違いがあるだけなので、これ以上の指摘は不要でしょう。 エラーメッセージを見て個別に修正してください。 (単純にたくさんのミスがあるのでたくさんのエラーが出ているだけです!) Teratail は質問に対して答えるというのがコンセプトであり、かわりにデバッグしてもらえることを期待しないでください。 https://teratail.com/help/avoid-asking 個別のエラーメッセージについて理解できない部分があればあらためて具体的な質問を投稿してください。
guest

0

次のコードが理解できれば、Vector と Iterator の実装ができるのではないでしょうか?

C++

1#include <iostream> 2#include <string> 3using namespace std; 4 5template <typename T> 6class Vector { 7 T *mData; 8 int mSize; 9 int mCapacity; 10public: 11 Vector(int n = 15) : mData(new T[n]), mSize(n), mCapacity(n) { } 12 ~Vector() { delete[] mData; } 13 T& operator[](int i) { return mData[i]; } 14 int Size() { return mSize; } 15 16 class Iterator { 17 T *mPtr; 18 public: 19 Iterator(T *p = nullptr) : mPtr(p) { } 20 Iterator operator++() { ++mPtr; return *this; } 21 bool operator!=(const Iterator& x) { return mPtr != x.mPtr; } 22 T& operator*() { return *mPtr; } 23 T* operator->() { return mPtr; } 24 }; 25 26 Iterator Begin() { return Iterator(mData); } 27 Iterator End() { return Iterator(mData + mSize); } 28}; 29 30int main() 31{ 32 Vector<int> a; 33 for (int i = 0; i < a.Size(); i++) 34 a[i] = i + 1; 35 for (Vector<int>::Iterator it = a.Begin(); it != a.End(); ++it) 36 cout << " " << *it; 37 cout << endl; 38 39 Vector<string> b(5); 40 b[0] = "a"; 41 for (int i = 1; i < b.Size(); i++) 42 b[i] = b[i-1] + char(b[i-1][i-1] + 1); 43 for (Vector<string>::Iterator it = b.Begin(); it != b.End(); ++it) 44 cout << it->size() << " " << *it << endl; 45}

Vector のコピーコンストラクタや代入演算子の定義は省略しました。

追記
質問のコードの Vector のコンストラクタの 15 は mSize ではなく mCapacity のデフォルト値だったんですね。
コンストラクタを次のように修正します。

C++

1 Vector(int n = 0) : mSize(n), mCapacity(n < 15 ? 15 : n) { 2 mData = new T[mCapacity]; 3 }

さらに、main の a は、Vector<int> a(20); にします。

追記2
main が少しずつ実行できるように作っていきましょう。

C++

1#include <iostream> 2using namespace std; 3 4template<typename T> 5class Vector { 6 T* mData; 7 int mSize; 8 int mCapacity; 9 10public: 11 Vector() { 12 mSize = 0; mCapacity = 15; mData = new T[mCapacity]; 13 } 14 ~Vector() { delete[] mData; } 15 void PushBack(const T& tItem) { 16 if (mSize < mCapacity) 17 mData[mSize++] = tItem; 18 else 19 cout << "to be implemented later\n"; 20 } 21 22 class Iterator { 23 int mCurrentIndex = 0; 24 T *mMyVector = nullptr; // not a pointer to Vector<T> 25 26 public: // コンストラクタは public に 27 Iterator(T *tWho, int tLocation) { // not a pointer to Vector<T> 28 mMyVector = tWho; 29 mCurrentIndex = tLocation; 30 } 31 T& GetData() { return mMyVector[mCurrentIndex]; } 32 void Next() { mCurrentIndex += 1; } 33 bool IsEqual(const Iterator& rhs) const { 34 return mMyVector == rhs.mMyVector && mCurrentIndex == rhs.mCurrentIndex; 35 } 36 }; // end of class Iterator definition 37 38 Iterator Begin() { return Iterator(mData, 0); } 39 Iterator End() { return Iterator(mData, mSize); } 40}; 41 42int main() 43{ 44 Vector<int> tTester; 45 tTester.PushBack(0); 46 tTester.PushBack(1); 47 tTester.PushBack(2); 48 49 for (Vector<int>::Iterator iter = tTester.Begin(); 50 !iter.IsEqual(tTester.End()); iter.Next()) { 51 cout << iter.GetData() << " "; 52 } 53 cout << endl; 54}

IsEqual は Vector のすべての要素が等しいかどうかではなく、
Iterator が同じ要素を指しているかどうかを調べるものです。

追記3
Iterator が Vector<T> へのポインタを持つように書くこともできます。

C++

1#include <iostream> 2using namespace std; 3 4template<typename T> 5class Vector { 6 T* mData; 7 int mSize; 8 int mCapacity; 9 10public: 11 Vector() { 12 mSize = 0; mCapacity = 15; mData = new T[mCapacity]; 13 } 14 ~Vector() { delete[] mData; } 15 void PushBack(const T& tItem) { 16 if (mSize < mCapacity) 17 mData[mSize++] = tItem; 18 else 19 cout << "to be implemented later\n"; 20 } 21 T& At(int i) { return mData[i]; } 22 23 class Iterator { 24 int mCurrentIndex = 0; 25 Vector<T> *mMyVector = nullptr; 26 27 public: // コンストラクタは public に 28 Iterator(Vector<T> *tWho, int tLocation) { 29 mMyVector = tWho; 30 mCurrentIndex = tLocation; 31 } 32 T& GetData() { return mMyVector->At(mCurrentIndex); } 33 void Next() { mCurrentIndex += 1; } 34 bool IsEqual(const Iterator& rhs) const { 35 return mMyVector == rhs.mMyVector && mCurrentIndex == rhs.mCurrentIndex; 36 } 37 }; // end of class Iterator definition 38 39 Iterator Begin() { return Iterator(this, 0); } 40 Iterator End() { return Iterator(this, mSize); } 41};

main は省略しました。

追記4
friend の意味を誤解していませんか?
質問のコードでは、class Iterator の中に frined class Vector; がありますが、
これは、Iterator の中のメンバ mCurrentIndex や mMyVector が private であっても
Vector の中のメンバ関数から参照できるようにするものです。
そんなものが必要でしょうか?

逆に class Vector の中に、frined class Iterator; と書けば、
Iterator の中のメンバ関数が Vector の中のメンバ mData などを参照できます。

例えば、追記3 のコードでそう書けば、Vectorのメンバ関数 At がなくても、
Iterator のメンバ関数 GetData が次のように書けます。

C++

1 T& GetData() { return mMyVector->mData[mCurrentIndex]; }

投稿2020/03/08 14:29

編集2020/03/09 15:21
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

do_Shiro_to

2020/03/08 22:26

ご返信ありがとうございます。 提示してくださったコードは、大体何をしているかは理解できたのですが、これでどうして動くのかはよくわかりませんでした。具体的に、私のコードとの違いを教えてもらえませんでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問