2015-12-21 1 views
1

Я написал программу сегодня, которая давала мне настоящую головную боль, когда она не срабатывала, как я ожидал этого.C++ 14 Вызов конструктора [с разными аргументами] из другого конструктора (тот же класс)

Итак, я написал короткий пример, который (почти) * воспроизводит проблему.

Надеюсь, это справедливо объяснимо в том, что он должен делать.

#include <iostream> 

class A 
{ 
    public: 

    enum class defaults 
    { 
     DEFAULT_A 
    }; 

    A(defaults default_val) 
    { 
     if(default_val == defaults::DEFAULT_A) 
     { 
      A("hello world"); 
     } 
    } 

    A(std::string str_) 
    { 
     str = str_; 
     flag = true; 
    } 

    std::string getStr() 
    { 
     return str; 
    } 

    bool getFlag() 
    { 
     return flag; 
    } 

    private: 

    bool flag; 
    std::string str; 

}; 

int main() 
{ 

    A a(A::defaults::DEFAULT_A); 

    std::cout << a.getStr() << std::endl; 
    std::cout << a.getStr().size() << std::endl; 
    if(a.getFlag()) 
    { 
     std::cout << "true" << std::endl; 
    } 
    else 
    { 
     std::cout << "false" << std::endl; 
    } 

} 

Компиляция и запуск кода: g++ --std=c++14 main.cpp && ./a.out

Компиляция на/с GCC версии 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2)

Выход: [с номерами строк]

1: 
2: 0 
3: true 

(это первая строка пустая строка.)

* Единственная вещь, которая отличный от этого примера и кода, над которым я работал сегодня, является то, что флаг в коде, который я написал ранее, был false не true, но это все еще НЕ то, что я ожидал от него - я ожидал, что это будет true. А также строка не была пустой, но она содержала «бессмысленные значения» - по крайней мере, не то, что я ожидал от нее.

Что я здесь сделал неправильно? Думаю, это действительно очевидно, но я просто не могу это понять. (Возможно, я работаю над той же проблемой для слишком долго?)

Edit:

Могу ли я сделать это, чтобы исправить эту проблему?

A(defaults default_val) 
{ 
    if(default_val == defaults::DEFAULT_A) 
    { 
     *this = A("hello world"); 
    } 
} 

ответ

1
A(defaults default_val) 
    { 
     if(default_val == defaults::DEFAULT_A) 
     { 
      A("hello world"); 
     } 
    } 

Если это if утверждение верно, вы не вызывая другой конструктор этого объекта.

Здесь A("hello world") создает новый временный объект, используя данный конструктор ... который немедленно уничтожается, потому что это временный объект.

+0

конечно - damnit – user3728501

+0

Как я могу сделать то, что я пытаюсь сделать? – user3728501

+0

Кроме того, 'a.getFlag()' вызывает неопределенное поведение, потому что 'flag' не был инициализирован –

3

Чтобы вызвать конструктор из другого конструктора (а делегирование конструктора), вы должны сделать это в списке инициализации конструктора:

 A(defaults default_val) : A("hello world") { 
      .. more stuff to do after alling the delegate ctor 

Проблема заключается в том, что это только позволяет сделать безусловными вызов делегата ctor (хотя вы можете использовать ?: в аргументе (аргументах), чтобы их значение было условным.) Нельзя условно вызвать делегата.

+0

Что я не сказал вам, что есть куча, если утверждения принимают решения о том, что делать, когда значение по умолчанию - это что-то другое, поэтому это решение не будет работать. – user3728501

+1

@ user3728501: Основываясь на том, что вы говорите, у вас, похоже, есть проблемы с дизайном в вашем коде, и вы пытаетесь пробиться, когда вам нужно сделать несколько шагов назад и пересмотреть рефакторинг кода вместо этого. – ray

+0

@ray Пожалуйста, прочитайте информацию, предоставленную с другими ответами или в моем вопросе о том, как проблема была решена/может быть решена. – user3728501

2

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

Затем вы можете использовать делегирование конструктора следующим образом:

#include <cassert> 
#include <iostream> 
#include <string> 

struct A 
{ 
    enum class defaults { first, second }; 

    A(defaults default_) 
     : A(DefaultToString(default_)) 
    { } 

    A(const std::string & str) 
     : s_(str) 
    { } 

    static std::string DefaultToString(defaults default_) 
    { 
     switch (default_) 
     { 
     case defaults::first: return "first"; 
     case defaults::second: return "second"; 
     } 

     assert(false); 
    } 

    std::string s_; 
}; 

int main() 
{ 
    A a1(A::defaults::first); 
    A a2(A::defaults::second); 
    A a3("other"); 
    std::cout << a1.s_ << " " << a2.s_ << " " << a3.s_ << "\n"; 
    return 0; 
} 
0

Вы можете использовать вспомогательные функции для делегирования конструктора:

namespace { 
    A MakeA(defaults default_val) 
    { 
     return (default_val == defaults::DEFAULT_A) ? 
      A("hello world") : 
      A(/* other constructor*/); 
    } 
} 

A::A(defaults default_val) : A(MakeA(default_val)) {} 

В настоящее время, вы создаете неиспользованные временные.

Смежные вопросы