Вы можете передать в функцию несколько параметров.
def printBill(bill)
становится:
def printBill(bill,hours):
, и вы называете его с помощью:
printBill(bill,hours)
Вам также нужно будет передать его getSavings таким же образом.
Я предпочитаю следующее соглашение:
typedef std::map< Foo, Bar > FooToBarMap
Я намеренно избегаю определения типов итераторов, я предпочитаю явно ссылаться на них as:
FooToBarMap::const_iterator
Поскольку итераторы уже являются de facto стандартным typename. Я считаю, что FooToBarMapConstIter на самом деле менее понятен для чтения при скимминге кода.
В отношении этих имен не существует общепринятого правила. Обычно я использую имя класса «value» с суффиксом Map. В вашем примере это будет SomeOtherClassMap . Я использую это соглашение, потому что обычно более интересно, что ваша карта содержит объекты «значения» типа SomeOtherClass , а затем вы просматриваете их с помощью «ключей» из SomeClass .
Мне наиболее интересна вторая часть вопроса. Я предпочитаю помещать typedef
в классы, которые их используют, когда для них есть логическое место, даже если они используются в других классах. Но это вызывает некоторые проблемы с прямыми объявлениями (которые мы часто используем для повышения скорости компиляции).
Например, в одном недавнем проекте у нас был класс под названием Io
со встроенным typedef под названием Point
, который создавал очень читаемый код - Io: : Пункт
очень четкий и читаемый. Но всякий раз, когда мы хотели использовать тип, нам приходилось включать объявление класса Io
, даже если все, что нам нужно, было объявление Io :: Point
, поскольку нет никакого способа (что я знаю) для прямого объявления типа, который находится в классе, объявленном вперед.
В этом случае мы сделали это обоими способами. Мы создали глобальный тип IoPoint
, а затем к нему typedef
d Io :: Point
(чтобы не пришлось изменять уже написанный код ). Не самый красивый ответ, но он сделал свою работу.
Что касается других частей:
Мы не используем никаких специальных соглашений для имен. Для карт мы часто используем * DescriptiveSomething *** Map ** (поскольку маловероятно, что мы когда-либо перейдем с карты на какой-либо другой тип контейнера), но если DescriptiveSomething достаточно информативен и не конфликтует с существующим именем, мы часто будем его использовать.
Обычно мы не утруждаем себя созданием определений типов для итераторов, поскольку легко (и очень удобно) просто использовать Type :: iterator
или Type :: const_iterator
. Тем не менее, мы выполняем иногда typedef, если имя типа настолько длинное, что Type :: const_iterator
делает код слишком «коренастым». (Не знаю лучшего способа сказать это, но вы, вероятно, знаете, что я имею в виду.)
Мы создаем разные определения типов для каждой концепции, даже если два из них определяют один и тот же тип. Они могут изменяться независимо друг от друга, поэтому наличие для них разных имен типов упрощает любой последующий рефакторинг. Во многих случаях это также делает код более читаемым.
Нет, просто имейте в виду общие правила именования идентификаторов (нет _
для начала с так далее). Кроме того, если в вашей организации есть руководство по кодированию, лучше всего придерживаться его.
Часто, когда вы определяете свой собственный шаблонный класс, он становится беспорядочным без typedefs - поэтому я бы создал их там как удобные ярлыки. Однако, если это действительно куча классов, я бы предпочел иметь их на уровне пространства имен
.
Мы используем следующее на моем рабочем месте:
typedef std::map WhateverMap; typedef WhateverMap::iterator WhateverIter; typedef WhateverMap::const_iterator WhateverCIter;
Что касается местоположения, то оно меняется. Если он специфичен для класса, он может быть в структуре Impl или в защищенной или закрытой области объявления класса. Если он более общий (используется в файлах, используется в API), мы помещаем его в отдельный заголовок стиля «FooTypes.h».
Обратите внимание, что, поскольку для нас часто бывает необходимо изменить базовый тип, мы можем использовать « Wh whatCollection "вместо" WheverVec "или" WheverList ". Нередки случаи, когда «WheverList» фактически определяется по типу для вектора или слайса, в зависимости от требуемой площади и характеристик производительности.
Я не знаю, существуют ли какие-либо формальные правила по этому вопросу, но я обычно добавляю определения типов в месте, наиболее подходящие для использования в проекте.
Что касается фактического имени типа typedef'd. Я называю это тем, что имеет смысл для typedef. Я не даю именам typedef никаких специальных соглашений, таких как префикс _t или что-то в этом роде. Например,
typedef stl::map<stl::string,Student> NameToStudentMap;
Обычно я определяю связанное имя с typedef, указывающее тип объекта.
Пример:
typedef std::vector<ClassCompStudent*> StudentCollection;
typedef std::map<std::string /*id*/, ClassCompStudent* /*pStudent*/> IDToStudentMap;
Кроме того, я определяю их как общедоступные в заголовке класса, в котором был создан объект. Это дает мне возможность изменять тип контейнера без нарушения клиентского кода.
class Test
{
public:
typedef std::vector<ClassCompStudent*> StudentCollection;
/* Users of Test need not know whether I use vector or list for
storing students. They get student collection and use it*/
bool getStudents(StudentCollection& studentList) const;
void print()
{
//do printing
}
private:
StudentCollection m_StudentList;
};
bool function(const Test& testObj)
{
//If StudentCollection gets changed to list, this code need not be changed.
StudentCollection aCollection;
testObj.getStudents(aCollection);
std::for_each(aCollection.begin(), aCollection.end(), std::mem_fun(&Test::print));
}
Интересный вопрос:
Я посмотрел в boost и вижу, что у них нет каких-либо глобальных правил, но наиболее часто используемые соглашения
typedef std::map< key, value > some_domain_specific_name_map;
или
typedef std::map< key, value > some_domain_specific_name_map_type;
также являются хорошей практикой для создания typedef для value_type или итераторов, обычно они имеют то же имя, что и map, но с окончанием _value_type, _iterator.
Использование слова «Карта» или «Вектор» в виде бесполезной записи. Это слова, связанные с реализацией, а не с бизнес-моделью.
Вам не нужно показывать, что этот тип является вектором или картой. Вы можете использовать список. Как
typedef std::vector<std::string> List;
typedef std::set<std::string> List;
Это оба списки строк. И это правда.
typedef std::map<std::string, Object> List;
or
typedef std::map<std::string, Object> NamedList;
Суть в том, что я не использую венгерскую нотацию.