Вот что я имею в виду:
class MyClass {
int arr1[100];
int arr2[100];
int len = 100;
void add(int* x1, int* x2, int size) {
for (int i = 0; i < size; i++) {
x1[i] += x2[i];
}
}
};
int main() {
MyClass myInstance;
// Fill the arrays...
myInstance.add(myInstance.arr1, myInstance.arr2, myInstance.len);
}
add
уже может получить доступ ко всем нужным переменным, так как это метод класса, так что это плохая идея? Есть ли причины, по которым я должен или не должен делать это?
add
метод без аргументов, который напрямую работает с его внутренними компонентами? Просто почему?add
метод, который принимает аргументы, но не существует как часть класса. Просто чистая функция для добавления двух массивов вместе.Ответы:
В классе могут быть вещи, которые я бы сделал по-другому, но чтобы ответить на прямой вопрос, мой ответ был бы
да это плохая идея
Моя главная причина этого в том, что вы не можете контролировать то, что передается в
add
функцию. Конечно, вы надеетесь, что это один из массивов-членов, но что произойдет, если кто-то передаст другой массив, размер которого меньше 100, или вы передадите длину больше 100?Что происходит, так это то, что вы создали возможность переполнения буфера. И это плохо во всем.
Чтобы ответить на еще несколько (для меня) очевидных вопросов:
Вы смешиваете массивы в стиле C с C ++. Я не гуру в C ++, но знаю, что в C ++ есть лучшие (более безопасные) способы работы с массивами
Если в классе уже есть переменные-члены, зачем вам их передавать? Это больше архитектурный вопрос.
У других людей с большим опытом работы с C ++ (я перестал использовать его 10 или 15 лет назад) могут быть более красноречивые способы объяснения проблем, и, вероятно, также возникнут и другие проблемы.
источник
vector<int>
было бы более подходящим; длина тогда будет бесполезна. В качестве альтернативыconst int len
, поскольку массив переменной длины не является частью стандарта C ++ (хотя некоторые компиляторы поддерживают его, потому что это дополнительная функция в C).std::array
который не затухает при передаче его параметрам, имеет более удобный способ получения его размера, копируется и имеет доступ с необязательной проверкой границ, но не требует дополнительных затрат Массивы в стиле C.Вызов метода класса с некоторыми переменными класса не обязательно плох. Но делать это извне класса - очень плохая идея и предполагает фундаментальный недостаток в вашей ОО-структуре, а именно отсутствие правильной инкапсуляции :
len
это длина массива, и использовать его последовательно. Это идет вразрез с принципом наименьшего знания . Такая зависимость от внутренних деталей класса чрезвычайно подвержена ошибкам и рискованна.len
на более современныеstd::vector<int>
), поскольку вам потребуется также изменить весь код, используя ваш класс.MyClass
объектам, повредив некоторые публичные переменные без соблюдения правил (так называемые инварианты классов )Вы должны рефакторинг вашего кода, и:
private
илиprotected
, если нет веских причин не делать этого.object.action(additional parameters for the action)
.источник
Если целью этой схемы является то, что вы хотите иметь возможность повторно использовать этот метод для данных, которые не поступают из этого экземпляра класса, тогда вы можете объявить его как
static
метод .Статический метод не принадлежит ни одному конкретному экземпляру класса. Это скорее метод самого класса. Поскольку статические методы не запускаются в контексте какого-либо конкретного экземпляра класса, они могут обращаться только к переменным-членам, которые также объявлены как статические. Учитывая, что ваш метод
add
не ссылается ни на одну из переменных-членов, объявленных вMyClass
, он является хорошим кандидатом для получения объявления как статического.Однако проблемы безопасности, упомянутые в других ответах, действительны: вы не проверяете, являются ли оба массива хотя бы
len
длинными. Если вы хотите написать современный и надежный C ++, вам следует избегать использования массивов. Используйте классstd::vector
вместо этого когда бы ни было возможно. В отличие от обычных массивов, векторы знают свой размер. Таким образом, вам не нужно отслеживать их размер самостоятельно. Большинство (не все!) Их методов также выполняют автоматическую проверку границ, которая гарантирует, что вы получите исключение, когда читаете или пишете после конца. Обычный доступ к массиву не выполняет проверку границ, что в лучшем случае приводит к segfault и может в худшем случае привести к уязвимости, связанной с переполнением буфера .источник
Метод в классе идеально манипулирует инкапсулированными данными внутри класса. В вашем примере нет никакой причины для метода add иметь какие-либо параметры, просто используйте свойства класса.
источник
Передача (часть) объекта в функцию-член - это нормально. При реализации своих функций вы всегда должны быть осведомлены о возможном алиасинге и его последствиях.
Конечно, контракт может оставить некоторые виды псевдонимов неопределенными, даже если язык их поддерживает.
Выдающиеся примеры:
С другой стороны, само-перемещение-назначение, хотя оно не должно взорваться на вашем лице, не должно быть запретным.
v.push_back(v[2]);
.std::copy()
предполагается, что пункт назначения не начинается внутри источника.Но у вашего примера другие проблемы:
this
. Он действует как бесплатная служебная функция, которая просто не в том месте.В итоге: да, этот пример плохой. Но не потому, что функция-член получает переданные объекты-члены.
источник
В частности, это плохая идея по нескольким веским причинам, но я не уверен, что все они являются неотъемлемой частью вашего вопроса:
vector<int>
сделает вашу жизнь прощеисточник
Это классический подход «C с классами» к C ++. На самом деле это не то, что написал бы любой опытный программист на С ++. С одной стороны, использование сырых массивов C во многом не рекомендуется, если только вы не реализуете библиотеку контейнеров.
Примерно так будет более уместно:
источник