[英]Standard containers encapsulation and range-based for loops
我正在設計一個類,該類具有兩個標准向量作為成員。 我希望能夠在向量元素上使用基於范圍的for循環,我想出了這個解決方案
#include <iostream>
#include <vector>
using namespace std;
class MyClass {
public:
void addValue1(int val){data1_.push_back(val);}
void addValue2(int val){data2_.push_back(val);}
vector<int> const & data1() const {return data1_;}
vector<int> const & data2() const {return data2_;}
// ...
private:
vector<int> data1_;
vector<int> data2_;
// ...
};
void print1(MyClass const & mc) {
for (auto val : mc.data1()){
cout << val << endl;
}
}
void print2(MyClass const & mc) {
for (auto val : mc.data2()){
cout << val << endl;
}
}
int main(){
MyClass mc;
mc.addValue1(1);
mc.addValue1(2);
mc.addValue1(3);
print1(mc);
}
顯然,因為我有兩個不同的向量,所以定義begin()
和end()
函數的選擇沒有意義。
我想問以下問題:
所提出的解決方案的缺點是兩個向量的內容不能更改(由於const
限定符)。 在需要修改向量元素的情況下,如何修改代碼? 編輯:修改應保留封裝
考慮到數據封裝,您是否認為對兩個向量返回( const
)引用是不好的做法?
使用gsl::span<int>
和gsl::span<const int>
。
這是最小的一個:
template<class T>
struct span {
T* b = 0; T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span( T* s, T* f ):b(s),e(f) {}
span( T* s, std::size_t len ):span(s, s+len) {}
template<std::size_t N>
span( T(&arr)[N] ):span(arr, N) {}
// todo: ctor from containers with .data() and .size()
// useful helpers:
std::size_t size() const { return end()-begin(); }
bool empty() const { return size()==0; }
T& operator[](std::size_t i) const { return begin()[i]; }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end())); }
// I like explicit defaults of these:
span() = default;
span(span const&) = default;
span& operator=(span const&) = default;
~span() = default;
};
現在您可以寫:
span<int const> data1() const {return {data1_.data(), data1_.size()};}
span<int const> data2() const {data2_.data(), data2_.size()};}
span<int> data1() {return {data1_.data(), data1_.size()};}
span<int> data2() {data2_.data(), data2_.size()};}
所提出的解決方案的缺點是兩個向量的內容不能更改(由於const限定符)。 在需要修改向量元素的情況下,如何修改代碼?
首先,您應該添加一個data1()
和data2()
非常量版本,這些版本返回對data1_
和data2_
成員的引用
vector<int> const & data1() const {return data1_;}
vector<int> const & data2() const {return data2_;}
vector<int> & data1() {return data1_;}
vector<int> & data2() {return data2_;}
第二:如果要修改print1()
的元素(例如),您必須將mc
作為非const引用接收
// ..........vvvvvvvvv no more const
void print1 (MyClass & mc) {
因此您可以更改mc
。
第三:在基於范圍的循環中,您必須將val
定義為參考,以便您可以對其進行修改,同時修改向量內的參考值
// ........V by reference
for ( auto & val : mc.data1() ) {
++val ; // this modify the value in the vector inside mc
cout << val << endl;
}
考慮到數據封裝,您是否認為對兩個向量返回一個(const)引用是不好的做法?
恕我直言:如果引用是const
,則根本不是:這是一個好習慣,因為允許安全使用該成員而無需重復該成員。
如果引用不是const
,那么將成員聲明為public不會有太大區別。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.