#c #stl #vector
#c #stl #векторный
Вопрос:
Я пытаюсь понять операторы, которые вам нужно перегружать при работе с пользовательскими классами в STL (SCL).
Кто-нибудь, пожалуйста, может сказать мне, что я делаю не так?
class myClass
{
public:
int data;
myClass()
{
data =0;
cout<<"Default const "<<endl;
}
myClass(int x)
{
data = x;
cout<<"Int constructor"<<endl;
}
myClass(const myClass amp;m)
{
cout<<"Copy constructor"<<endl;
}
bool operator == (const myClass amp;temp)
{
cout<<"Operator called amp;";
return data == temp.data;
}
bool operator == (const myClass *temp)
{
cout<<"Operator called *";
return data == temp->data;
}
};
int main ()
{
/*
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), meObj);
*/
vector<myClass*> myVec;
myClass temp;
myVec.push_back(amp;temp);
myClass temp2(19);
myVec.push_back(amp;temp2);
myClass temp3(19);
vector<myClass*>::iterator it = find(myVec.begin(),myVec.end(),amp;temp2); //works
if(it!=myVec.end())
{
cout<<"Value is "<<(*it)->data;
}
vector<myClass*>::iterator dit = find(myVec.begin(),myVec.end(),amp;temp3); //fails
if(dit!=myVec.end())
{
cout<<"Value is "<<(*dit)->data;
}
cout << endl;
return 0;
}
Пожалуйста, поправьте меня, если я ошибаюсь, но первая находка работает так же, как и сравнение адресов. Что мне нужно перегрузить, чтобы вышеприведенное сработало?
Имеют ли смысл обе подписи?
bool operator == (const myClass amp;temp); // seen in many places
bool operator == (const myClass *temp); // what if two pointer types of same object are being compared?
Приветствия!
Комментарии:
1. Вам действительно нужен вектор<T *> в вашем случае? Если да, пожалуйста, ознакомьтесь с контейнером указателей Boost ( boost.org/doc/libs/1_46_1/libs/ptr_container/doc /… ).
2. Ну, это всего лишь эксперимент с пониманием. Как я всегда думал, имея дело с динамическим распределением памяти, вы будете «сохранять» адрес элемента, а не элемент дважды в вашей программе. т.Е. один раз в новой и одной копии в контейнере.
Ответ №1:
Перегрузки оператора должны иметь хотя бы один пользовательский тип. Таким образом, вы не можете перегрузить, operator==
например, два указателя.
Ваш myClass::operator==(const myClass *temp)
действителен в том смысле, что он компилируется, но имеет очень мало семантического смысла и не рекомендуется (существует очень мало ситуаций, в которых вы хотели бы это сделать T x; T *y; ... (x == y)
).
Для вашей ситуации, когда у вас есть вектор указателей, вы можете рассмотреть std::find_if
, который принимает предикат. Что-то вроде:
class CompareByPointer
{
public:
explicit CompareByPointer(const myClass amp;p) : p(p) {}
bool operator() (const myClass amp;rhs) const { return p->data == rhs->data; }
private:
const myClass amp;p;
};
...
find_if(myVec.begin(), myVec.end(), CompareByPointer(amp;temp2));
[В качестве дополнительного примечания, вам обычно следует определять функции-члены const
везде, где это возможно. Таким образом, ваши перегрузки оператора должны быть const
.]
Комментарии:
1. Возможно, я чего-то не понимаю, означает ли это, что вы не можете использовать операции типа find для контейнера, который содержит указатели пользовательских типов?
2. @Ricko: Вы можете, но при этом будут сравниваться сами указатели, а не то, на что они указывают.
3. @Ricko: и да, и нет. Как уже было сказано, перегруженные операторы могут применяться только к определяемым пользователем типам. Но вместо
find
вы можете использоватьfind_if
, например, который вместо использования перегруженных операторов использует заданную пользователем функцию-предикат4. Спасибо, ребята! Еще одна вещь, которую следует уточнить, когда вы говорите, что существует хотя бы один пользовательский тип, имеете ли вы в виду другой случай, как неявное преобразование встроенных типов в пользовательские типы с помощью неявного конструктора?
5. @Ricko: Компилятор попытается устранить перегрузку оператора максимум одним неявным преобразованием.
Ответ №2:
В примере кода вы не вставили amp;temp3
в myVec
. Поэтому имеет смысл, чтобы второй std::find
потерпел неудачу.
Комментарии:
1. да, это было сделано специально. Я хотел посмотреть, есть ли какие-либо операторы, которые я мог бы перегрузить, чтобы получить «правильный» логический результат.
Ответ №3:
Что вы подразумеваете под «работой» в этом случае? Как правило, когда вы сохраняете указатели, это происходит потому, что объекты действительно имеют идентификацию, и сравнение адреса — это правильная вещь. В противном случае вам, вероятно, следует сохранять значения (хотя есть исключения). В любом случае, вы всегда можете использовать find_if
и любые критерии сравнения, которые вы хотите. В любом случае, я использую что угодно, кроме простейших типов, find_if
чаще, чем find
в любом случае; обычно вы ищете не равенство, а какой-то определенный тип соответствия. Здесь, например, вы, скорее всего, захотите что-то вроде:
std::vector<MyClass>::iterator it = std::find_if( myVect.begin(), myVect.end(),
boost::bind(amp;MyClass::id, _1, 19) );
(Предположим, что data
здесь есть какой-то идентификатор, и что вы предоставили функцию-член, myClass::id()
чтобы прочитать его.)
Комментарии:
1. Под работой я подразумеваю, что сравнение в идеале должно возвращать true. Это нечто похожее на побитовое сравнение в отличие от фактического сравнения значений.
2. Я все еще не уверен, что понимаю. При каких условиях сравнение должно возвращать значение true? Как я уже сказал, вы решили разобраться с указателями. Наиболее вероятная причина заключается в том, что каждый объект имеет идентификатор, и объекты являются «равными» только в том случае, если они являются одним и тем же объектом. В противном случае используйте значения, а не указатели. (Это один из моих пунктов — другой заключается в том, что вы, вероятно, хотите
find_if
в любом случае, поскольку вы не хотите создавать полный объект только для проверки, равен ли идентификатор объекта 19.)