C++ нотация

C++ нотация с использованием только маленьких букв

Е.А.Охотников
2002.04.09, 2003.06.23, 2004.03.03, 2004.10.12, 2005.01.10

Именование файлов

Маленькими буквами, отдельные слова разделяются подчеркиванием.

Заголовочные файлы имеют расширение .hpp

Файлы реализации имеют расширение .cpp

header_file.hpp
source_file.cpp
my_complex_class.hpp
my_complex_class.cpp

Если в директиве include нужно указать имя файла вместе с именами каталогов, то нужно использовать прямые косые:

#include <so_lib/h/so_lib.hpp>

#include <auto_ptr_2/h/vect_ptr.hpp>

#include <simexpl_1/delarue_2/card_type/h/card_type.hpp>

При использовании #include отдельные логически связанные группы заголовочных файлов нужно отделять пустой строкой:

#include <stdafx.h>

#include <string>
#include <vector>

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#include <so_lib/h/so_lib.hpp>

#include <auto_ptr_2/h/vect_ptr.hpp>
#include <auto_ptr_2/h/obj_ptr.hpp>

#include <simexpl_1/h/log_macros.hpp>
#include <simexpl_1/h/card_representation.hpp>
#include <simexpl_1/h/reader_thread.hpp>
#include <simexpl_1/h/card_info.hpp>

#include <simexpl_1/delarue_2/card_type/h/card_type.hpp>

Именование пространств имен

Пишутся только маленькими буквами. Использование заглавных букв возможно только для значащих аббревеатур (например, SMNP, HTTP, SMTP, POP3 и т.д.), хотя аббревеатуры так же можно записывать маленькими буквами).

Каждое значимое слово отделяется подчеркиванием.

Если имя состоит из нескольких самостоятельных названий, то названия могут разделяться дополнительным подчеркиванием.

После закрывающей фигурной скобки пространства имен желательно указывать в комментарии к какому пространству имен относится эта скобка.

namespace oess_sequence_1
{

namespace impl
{
} /* namespace impl */

} /* namespace oess_sequence_1 */

Именование типов

Завершаются суффиксом _t.

Пишутся только маленькими буквами. Использование заглавных букв возможно только для значащих аббревеатур (например, SMNP, HTTP, SMTP, POP3 и т.д.), хотя аббревеатуры так же можно записывать маленькими буквами).

Каждое значимое слово отделяется подчеркиванием.

Если имя состоит из нескольких самостоятельных названий, то названия могут разделяться дополнительным подчеркиванием.

Для типа указателя на функцию должен использоваться префикс pfn.

Для типа исключения может использоваться суффикс _ex_t.

struct	my_struct_t {...};
typedef unsigned char	uint8_t;
class	io_subsystem_t { ... };
class	io_subsystem_iostream_t : public io_subsystem_t { ... };
class	io_subsystem_socket_tcp_t : public io_subsystem_t { ... };
class	io_subsystem_socket_udp_t : public io_subsystem_t { ... };
typedef uint8_t ( * pfn_some_function_t )();
class	out_of_range_t { ... };
class	file_not_found_ex_t : public std::exception { ... };

Именование функций

Начинаются с маленькой буквы.

Пишутся только маленькими буквами. Использование заглавных букв возможно только для значащих аббревеатур (например, SMNP, HTTP, SMTP, POP3 и т.д.), хотя аббревеатуры так же можно записывать маленькими буквами).

Каждое значимое слово отделяется подчеркиванием.

Если имя состоит из нескольких самостоятельных названий, то названия могут разделяться дополнительным подчеркиванием.

Если не получает аргументов, то описывается как f(), а не как f( void ).

Может иметь суффикс _, для того, чтобы отличать от методов.

Описание возвращаемого значение делается на отдельной строке (очень полезно если тип возвращаемого значения имеет длинное имя).

void
some_fuction();

void
init_io_subsystem_();

void
init_io_subsystem__iostream_( iostream & o );

Именование методов

Начинаются с маленькой буквы.

Пишутся только маленькими буквами. Использование заглавных букв возможно только для значащих аббревеатур (например, SMNP, HTTP, SMTP, POP3 и т.д.), хотя аббревеатуры так же можно записывать маленькими буквами).

Каждое значимое слово отделяется подчеркиванием.

Если имя состоит из нескольких самостоятельных названий, то названия могут разделяться дополнительным подчеркиванием.

Если не получает аргументов, то описывается как m(), а не как m( void ).

Пары методов для получения и изменения какого-либо значения можно именовать двумя способами:

  • query_<что-то> и set_<что-то>, а не get_<что-то> и set_<что-то> (поскольку set и get различаются только одной буквой). const std::string & query_font_name() const; void set_font_name( const std::string & name );
  • <что-то>() const для получения значения и set_<что-то> для изменения значения. const std::string & font_name() const; void set_font_name( const std::string & name ); Данный способ предпочтительнее, т.к. используются более короткие имена при обращении к getter-ам.

Описание возвращаемого значение делается на отдельной строке (очень полезно если тип возвращаемого значения имеет длинное имя).

class	some_class_t {
	public :
		void
		some_method();

		void
		init();

		virtual void
		init_io_subsystem();

		static void
		init_io_subsystem__iostream( iostream & o );
};

Именование переменных (локальных переменных, аргументов методов и функций)

Начинаются с маленькой буквы.

Пишутся только маленькими буквами. Использование заглавных букв возможно только для значащих аббревеатур (например, SMNP, HTTP, SMTP, POP3 и т.д.), хотя аббревеатуры так же можно записывать маленькими буквами).

Каждое значимое слово отделяется подчеркиванием.

Если имя состоит из нескольких самостоятельных названий, то названия могут разделяться дополнительным подчеркиванием.

void	some_fuction_( some_type_t & some_argument ) {
	my_class_t	my_object;
	io_subsystem_iostream_t	iostream_subsystem;
}

Именование глобальных переменных

Могут начинаются с префикса g_.

В остальном должны следовать правилам именование переменных.

my_class_t	g_my_class;
io_subsystem_socket_tcp_t	g_subsys_sock_TCP;
io_subsystem_socket_udp_t	g_subsys_sock_UDP;

Префикс g_ не обязателен, если имя переменной однозначно разрешается в рамках текущего контекста.

namespace	cfg
{
	// Глобальная переменная.
	configuration_t	current;
}

// Использование глобальной переменной.
configuration_t my_config = cfg::current;

Именование полей классов (структур)

Начинаются с префикса m_.

В остальном должны следовать правилам именование переменных.

struct	info_t {
	int	m_id;
	int	m_type;
	int	m_priority;
	char	m_short_name;
	std::string	m_full_name;
};

class	my_class_t {
	protected :
		std::string	m_full_name;

		static io_sybsystem_t	m_io_subsys;
};

Использование венгерской нотации в именах переменных

Венгерская нотация в именах переменных НЕ ИСПОЛЬЗУЕТСЯ.

Именование констант

Могут начинатся с префикса c_. Префикс можно опускать, если константы определяются в контексте, исключающем их двоякое толкование. Например, в пространстве имен, предназначенном для описания кодов ошибок, если все коды представляются константами. В этом случае префикс c_ избыточен.

В остальном должны следовать правилам именование переменных.

const size_t	c_max_size = 15;
const char *	c_default_file_name = "noname.cpp";

namespace error_code
{
	const int no_error = 0;
	const int not_found = 1;
	const int bad_argument = 2;
}

Именование элементов перечисления

Могут начинатся с префикса e_. Префикс можно опускать, если перечисление определяются в контексте, исключающем его двоякое толкование. Например, в каком-либо классе. В этом случае префикс e_ избыточен, поскольку доступ к элементам перечисления осуществляется через имя класса.

В остальном должны следовать правилам именование переменных.

Если в нутри одного блока (например, описания класса) определяется несколько перечислений, то каждый элемент перечисления может иметь специальный префикс, уникальный для перечисления.

enum error_t {
	e_none,
	e_bad_argument,
	e_io_error,
	e_no_memory
};

class	gsm_sms_text_t {
	public :
		enum data_coding_scheme_t {
			default_coding_scheme,
			general_coding_scheme,
			sim_specific_coding_scheme
		};

		enum default_coding_scheme_t {
			def_default_alphabet = 0x01,
			def_unicode_alphabet = 0x03,
			def_byte_alphabet = 0x07,
			def_sim_specific = 0x04
		};

		enum general_coding_scheme_t {
			gen_default_alphabet = 0x10,
			gen_unicode_alphabet = 0x20,
			gen_byte_alphabet = 0x40,
			gen_sim_specific = 0x60
		};
};

Длина строки

Длина строки не должна превышать 70 символов. Оптимальная длина 60-65 символов при размере табуляции 4 символа.

Фигурные скобки и отступы

Все отступы должны формироваться только при помощи табуляции.

Если строка становится слишком длинной, то продолжение пишется в новой строке с отступом в одну табуляцию или две табуляции. В некоторых случаях (например, в сложных условях операторов if, while, for и т.д. за которыми идет всего один оператор, более удобно использовать отступ в две табуляции).

Не нужно выравнивать продолжение строки по каким-либо открывающим круглым или квадратным скобкам, началу вызова функции, началу варианта case в switch и т.д. Ниже перечислены НЕПРАВИЛЬНЫЕ примеры:

// Неправильно
void	some_class_t::some_method( some_type1_t & arg_type1,
                                   some_type2_t & arg_type2 );

// Неправильно
if( 0 != ( my_file = fopen( file_name_manager->query_file_name(
                                                  my_file_type ),
                            file_name_manager->query_open_mode() ) ) )

// Неправильно
i += my_data[ my_cross_ref_data[ j * query_line() +
                                 k * query_column() ] +
              delta ];

// Неправильно
inline type_with_long_name_t *	some_inline_fuction( int arg )
                                {
                                    return new type_with_long_name_t(
                                                                     arg );
                                }

// Неправильно
switch( operation_type ) {
    case c_op_type1 : {
                      call_op_type1_handler();
                      break; }
    case c_op_type2 : {
                      call_op_type2_handler();
                      break; }
}

Правильный формат отступов определяется тем, что чтение происходит сверху вниз и слева направо. При переходе на новую строку глазам проще вернуться в крайнюю левую позицию, чем на произвольную позицию в центре или в правом конце строки.

Для открывающих и закрывающих скобок возможны два подхода:

  • открывающая скобка ставиться в конце строки, а закрывающая на отдельной строке;
  • открывающая и закрывающая скобки ставятся на отдельных строках в одной и той же позиции. При этом для открывающих и закрывающих скобок может быть сделан дополнительный отступ вправо (т.н. GNU-стиль).

Правильные варианты (с использованием отступа в одну табуляцию):

void
some_class_t::some_method(
	some_type1_t & arg_type1,
	some_type2_t & arg_type2 );

if( 0 != ( my_file = fopen(
	file_name_manager->query_file_name( my_file_type ),
	file_name_manager->query_open_mode() ) ) )

i += my_data[
	my_cross_ref_data[ j * query_line() +
		k * query_column() ] +
	delta ];

inline type_with_long_name_t *
some_inline_fuction( int arg )
{
	return new type_with_long_name( arg );
}
// Или
inline type_with_long_name_t *
some_inline_fuction( int arg ) {
	return new type_with_long_name( arg );
}
// Или
inline type_with_long_name_t *
some_inline_fuction( int arg )
	{
	return new type_with_long_name( arg );
	}
// Или
inline type_with_long_name_t *
some_inline_fuction( int arg )
	{
		return new type_with_long_name( arg );
	}

switch( operation_type ) {
	case c_op_type1 : {
		call_op_type1_handler();
	}
	break;

	case c_op_type2 : {
		call_op_type2_handler();
	}
	break;
}
// Или
switch( operation_type )
{
	case c_op_type1 :
	{
		call_op_type1_handler();
	}
	break;

	case c_op_type2 :
	{
		call_op_type2_handler();
	}
	break;
}
// Или
switch( operation_type )
	{
	case c_op_type1 :
		{
		call_op_type1_handler();
		}
	break;

	case c_op_type2 :
		{
		call_op_type2_handler();
		}
	break;
	}
// Или
switch( operation_type )
	{
		case c_op_type1 :
			{
				call_op_type1_handler();
			}
		break;

		case c_op_type2 :
			{
				call_op_type2_handler();
			}
		break;
	}

В этих случаях удобно делать отступ в две табуляции:

// Здесь сразу видно, что throw не относиться к условию if.
if( trace_no != config.trace_mode() &&
		trace_last != config.trace_mode() &&
		trace_all != config.trace_mode() )
	throw std::logic_error( "unsupported trace mode" );

// Здесь сразу видно, где находиться тело for.
for( my_object_map_t::const_iterator it = m_map.begin();
		it != m_map.end();
		++it )
	it->second.do_calculation( config, params, result );

Пробелы и скобки

Пробелов должно быть как можно больше. Каждый значащий элемент выражения должен выделяться пробелами.

Не должно быть двух или более идущих подряд пробелов.

Не должно быть пробела между идентификатором (ключевым словом) и открывающей скобкой.

После открывающей и перед закрывающей скобкой должны быть пробелы. Исключением является приведение типа в стиле C.

void
my_func_(
	file_name_manager_t * file_name_manager,
	void * data ) {
	FILE * my_file;
	if( 0 != ( my_file = fopen(
		file_name_manager->query_name( c_my_file_name ),
		file_name_manager->query_open_mode( c_my_open_mode ) ) ) ) {
		try {
			my_data_object_t * data_obj = (my_data_object_t *)data;
			data_obj->save_data( my_file );
		}
		catch( invalid_data_t & x ) {
		}

		fclose( my_file );
	}
}

Комментарии

Комментарии не должны превышать максимальную длину строки.

Комментарии должны предшествовать описаниям и действиям, а не следовать за ними справа или снизу.

Многострочные коментарии должны использоваться для больших фрагментов поясняющего текста. Например для подробного описания назначения класса.

Для изъятия больших фрагментов кода при отладке нужно использовать не комментарии, а инструкции #if 0/#endif

Способ описания и реализации класса

В идеале, для нешаблонного класса, не описывающего доступных вложенных типов, должна использоваться только одна секция public и либо одна секция protected, либо одна секция private, либо одна секция protected и одна секция private.

При реализации класса сначала должны следовать объявления статических переменных, затем конструкторов и дейструкторов, затем остальных методов. Желательно, что-бы реализация методов соблюдала порядок декларации методов в описании класса (если это позволяет среда разработки).

Источник: ссылка