Я бы использовал переменную среды для размещения вашего приложения. Кажется, это лучший способ запускать инструменты go, поскольку тестовые программы можно запускать из временного местоположения.
// get home dir of app, use MYAPPHOME env var if present, else executable dir.
func exeDir() string {
dir, exists := os.LookupEnv("MYAPPHOME")
if exists {
return dir
} else {
ex, err := os.Executable()
if err != nil {
panic(err)
}
exPath := path.Dir(ex)
return exPath
}
}
Компилятору позволяют сделать одно неявное преобразование для разрешения параметров к функции. То, что это означает, - то, что компилятор может использовать конструкторов, вызываемых с единственный параметр для преобразования от одного типа до другого для получения правильного типа для параметра.
Вот класс в качестве примера с конструктором, который может использоваться для неявных преобразований:
class Foo
{
public:
// single parameter constructor, can be used as an implicit conversion
Foo (int foo) : m_foo (foo)
{
}
int GetFoo () { return m_foo; }
private:
int m_foo;
};
Вот простая функция, которая берет Foo
объект:
void DoBar (Foo foo)
{
int i = foo.GetFoo ();
}
и вот то, где эти DoBar
функция вызвана.
int main ()
{
DoBar (42);
}
аргумент не Foo
объект, а int
. Однако там существует конструктор для Foo
, который берет int
, таким образом, этот конструктор может использоваться для преобразования параметра в корректный тип.
компилятору позволяют сделать это однажды для каждого параметра.
Добавление префикса explicit
ключевое слово конструктору препятствует тому, чтобы компилятор использовал того конструктора для неявных преобразований. Добавление его к вышеупомянутому классу создаст ошибку компилятора при вызове функции DoBar (42)
. Теперь необходимо призвать к преобразованию явно с [1 111]
причина, которую Вы могли бы хотеть сделать, это должно избежать случайной конструкции, которая может скрыть ошибки. Изобретенный пример:
MyString(int size)
класс с конструктором, который создает строку данного размера. У Вас есть функция print(const MyString&)
, и Вы звоните print(3)
(когда Вы на самом деле намеревались звонить print("3")
). Вы ожидаете, что это распечатает "3", но это печатает пустую строку длины 3 вместо этого. Предположим, у Вас есть класс String
:
class String {
public:
String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
Теперь, если Вы пробуете:
String mystring = 'x';
символ 'x'
будет неявно преобразован в int
и затем String(int)
, конструктора вызовут. Но, это не то, что, возможно, предназначил пользователь. Так, для предотвращения таких условий мы определим конструктора как explicit
:
class String {
public:
explicit String (int n); //allocate n bytes
String(const char *p); // initialize sobject with string p
};
В C++ конструктора только с одним обязательным параметром считают неявной функцией преобразования. Это преобразовывает тип параметра в тип класса. Является ли это хорошей вещью или не зависит от семантики конструктора.
, Например, если у Вас есть строковый класс с конструктором String(const char* s)
, это, вероятно, точно, что Вы хотите. Можно передать const char*
функции, ожидая String
, и компилятор автоматически создаст временный файл String
объект для Вас.
, С другой стороны, если у Вас есть буферный класс, конструктор которого Buffer(int size)
берет размер буфера в байтах, Вы, вероятно, не хотите, чтобы компилятор бесшумно превратил int
с в Buffer
с. Для предотвращения этого Вы объявляете конструктора с explicit
ключевое слово:
class Buffer { explicit Buffer(int size); ... }
Тот путь,
void useBuffer(Buffer& buf);
useBuffer(4);
становится ошибкой времени компиляции. Если Вы хотите передать временный файл Buffer
объект, необходимо сделать так явно:
useBuffer(Buffer(4));
, Таким образом, если Ваш конструктор единственного параметра преобразовывает параметр в объект Вашего класса, Вы, вероятно, не хотите использовать explicit
ключевое слово. Но если у Вас есть конструктор, который просто, оказывается, берет единственный параметр, необходимо объявить, что это как [1 113] препятствует тому, чтобы компилятор удивил Вас неожиданными преобразованиями.
Это уже обсуждалось ( что такое явный конструктор ). Но я должен сказать, что здесь отсутствуют подробные описания.
Кроме того, всегда полезно создавать конструкторы с одним аргументом (включая те, которые имеют значения по умолчанию для arg2, arg3, ...), как уже говорилось . Как всегда с C ++: если вы этого не сделаете - вы захотите, чтобы вы это сделали ...
Еще одна хорошая практика для классов - сделать создание копий и присваивание частными (то есть отключить), если вам действительно не нужно это реализовывать. Это позволяет избежать возможных копий указателей при использовании методов, которые C ++ создаст для вас по умолчанию. Другой способ сделать это - использовать boost :: noncopyable.
create
вместоudpate
, или я должен использовать обоих? – Billie 12 January 2014 в 12:11