Во-первых, извините за название. Я не мог сжать то, что я пытаюсь спросить, в одну фразу :(
Я читал этот пост, и он каким-то образом заставил меня задуматься о функции указатели. В частности, мне было интересно, почему «плохо» (или, по крайней мере, редко встречается) передавать функции-члены класса в качестве параметров функции, а затем использовать этот указатель на существующий объект внутри этой функции.
Предположим, у меня есть шаблонный класс «Контейнер», который хранит одну переменную типа T и предоставляет метод для получения константной ссылки на эту переменную.
template<class T>
class Container {
public:
Container(T anObject) {
m_data = anObject;
}
const T& getData() const {
return m_data;
}
private:
T m_data;
};
Теперь я хотел бы иметь возможность выполнять функции-члены T на m_data, но я не хочу делать getData() неконстантным, потому что это позволило бы все виды других шалостей с возвращаемой ссылкой. Мое решение состоит в том, чтобы добавить новую общедоступную функцию mod_data(...) в Container, которая принимает указатель функции на функцию-член T в качестве параметра и выполняет ее на m_data; вот так:
// ...
void modifyData( void(typename T::*funcptr)(void) ) {
(m_data.*fptr)();
}
// ...
Как есть, это приведет к сбою и сгорит, если T является указателем. Для тестирования я только что создал специальный шаблон для Container<T*>
, чтобы решить эту проблему, но я уверен, что есть более элегантный способ.
Очень истолкованный пример показывает, что это, кажется, работает так, как задумано:
// example class to be used with Container
class Data {
public:
Data() {m_count = 0; }
void incrementCount() { m_count++; }
int getCount() const { return m_count; }
private:
int m_count;
};
// ... in main.cpp:
Data dat;
Container<Data*> DCont(dat);
std::cout << cl.getData()->getCount() << std::endl; // outputs 0
DCont.modifyData<Data>(&Data::incrementCount);
std::cout << cl.getData()->getCount() << std::endl; // outputs 1
// compiler catches this:
// DCont.modifyData<SomeOtherClass>(&Data::incrementCount);
// this probably does something bad:
// DCont.modifyData<SomeOtherClass>(&SomeOtherClass::someFunc);
Инстинктивно это кажется ужасно извращенным способом работы, и я никогда не видел кода, который бы работал так. Но мой вопрос в том, есть ли причина производительности/безопасности, почему что-то подобное плохо, или это просто считается плохой практикой? Если это «просто» плохая практика, то почему?
Очевидные ограничения, о которых я мог подумать, это что-то вроде // DCont.modifyData(&SomeOtherClass::someFunc); вероятно, произойдет сбой во время выполнения, но я думаю, что это можно решить, сравнив тип U с T в incrementData(). Кроме того, modifyData принимает только функции void (*)(), но это, вероятно, можно решить с помощью шаблонов с переменным числом аргументов.
Этот пример, очевидно, очень истолкован и не очень хорошо реализован, но я думаю (надеюсь?), что этого достаточно, чтобы объяснить, о чем я говорю.
Спасибо!
РЕДАКТИРОВАТЬ: Кажется, есть некоторая путаница в том, в чем заключается вопрос. По сути, это сценарий, о котором я говорю: у вас есть набор классов из какой-то библиотеки, которые вы пытаетесь сохранить в контейнере, и еще одна функция, которая генерирует определенные контейнеры; Теперь вы хотите, чтобы пользователь мог вызывать существующие функции-члены для объектов внутри этих контейнеров, но не изменять фактические объекты (например, при возврате неконстантной ссылки с помощью геттера). Фактическая реализация, вероятно, будет использовать какой-то вариативный шаблон, чтобы быть полезным, но мне нужно подумать над этим еще немного, прежде чем публиковать пример кода.
Короче говоря, я хотел бы ограничить доступ пользователя к членам контейнера только функциями-членами этого члена. Есть ли более простой способ сделать это, или этот способ не работает так, как я собирался?
void f()
, привести его к типу вашего класса, а затем его функция будет работать с вашим указателемthis
? - person Gir   schedule 14.08.2012data
, которые не должны существовать в первую очередь (в вашем примере их нет). Разница с открытием непостоянного доступа во многих случаях невелика и, вероятно, не оправдывает обстоятельства. - person Peter - Reinstate Monica   schedule 11.04.2016