2016-06-22 3 views
1

У меня есть два класса A и B. bclass типа B является постоянным членом класса A; то, что я хочу сделать, это инициализировать класс bclass со значениями по умолчанию, если объект B не указан A. Что-то вроде этого:Инициализировать член класса const со значением по умолчанию

#include <iostream> 
#include <string> 
#include <unistd.h> 

using namespace std; 

class B{ 
public: 
    B(string Bs): Bstring(Bs){ 
    cout << "B constructor: " << Bstring << endl; 
    } 

    ~B(){ 
    cout << "B destructor: " << Bstring << endl; 
    } 

private: 
    const string Bstring; 
}; 

class A{ 
public: 
    A(const B subb = B("mmmmm")): bclass(subb){ 
    cout << "A constructor." << endl; 
    } 

    ~A(){ 
    cout << "A destructor." << endl; 
    } 

private: 
    const B bclass; 
}; 

int main(void){ 
    A a; 
    cout << "doing work..." << endl; 
    sleep(2); 
    return 0; 
} 

Выход:

B constructor: mmmmm 
A constructor. 
B destructor: mmmmm 
doing work... 
A destructor. 
B destructor: mmmmm 

Дело в том, что я строить 2 B классы, когда только один нужен (?)! И как-то, конструктор B вызывается только один раз, а деструктор называется дважды ... Что происходит ?!

EDIT 1:

После прочтения (большой) ответ @WhiZTiM, я добавил следующие два обновления ...

Следующий код объясняет, когда второй конструктор вызывается:

#include <iostream> 
#include <string> 
#include <unistd.h> 

using namespace std; 

class B{ 
public: 
    B(string Bs): Bstring(Bs){ 
    cout << "B constructor: " << Bstring << endl; 
    } 
    B(const B& bobj): Bstring(bobj.Bstring + "(copy)"){ 
    cout << "B copy constructor: " << Bstring << endl; 
    } 

    ~B(){ 
    cout << "B destructor: " << Bstring << endl; 
    } 

private: 
    const string Bstring; 
}; 

class A{ 
public: 
    A(const B& subb = B("mmmmm")): bobj(subb){ 
    cout << "A constructor." << endl; 
    } 

    ~A(){ 
    cout << "A destructor." << endl; 
    } 

private: 
    const B bobj; 
}; 

int main(void){ 
    A a; 
    cout << "doing work..." << endl; 
    sleep(2); 
    return 0; 
} 

выход:

B constructor: mmmmm 
B copy constructor: mmmmm(copy) 
A constructor. 
B destructor: mmmmm 
doing work... 
A destructor. 
B destructor: mmmmm(copy) 

Как @WhiZTiM указал на меня, компилятор подал третий вызов конструктору B (спасибо!).

EDIT 2: Как я хочу только 1 объект B, лучше всего использовать указатели. Код должен быть:

#include <iostream> 
#include <string> 
#include <unistd.h> 

using namespace std; 

class B{ 
public: 
    B(const string Bs): Bstring(Bs){ 
    cout << "B constructor: " << Bstring << endl; 
    } 
    B(const B& bobj): Bstring(bobj.Bstring){ 
    cout << "copying an existing B object." << endl; 
    } 

    ~B(){ 
    cout << "B destructor: " << Bstring << endl; 
    } 

private: 
    const string Bstring; 
}; 

class A{ 
public: 
    A(B* subb = new B("mmmmm")): objb(subb){ 
    cout << "A constructor." << endl; 
    } 

    ~A(){ 
    cout << "A destructor." << endl; 
    delete objb; 
    } 

private: 
    const B* const objb; 
}; 

int main(void){ 
    A a1; // This will call the default B constructor. 
    A a2(new B("ooooo"));// This is calling a non default B object constructor. 
    cout << "doing work..." << endl; 
    sleep(2); //I need more motivation... 
    return 0; 
} 

Это выход: (?)

B constructor: mmmmm 
A constructor. 
B constructor: ooooo 
A constructor. 
doing work... 
A destructor. 
B destructor: ooooo 
A destructor. 
B destructor: mmmmm 

Большое спасибо @WhiZTiM

+0

'B' не является постоянным подклассом. 'A' является составным объектом' B' – WhiZTiM

+1

Предпочитают 'A (const B & subb = B (" mmmmm "))'. 'A (const B subb = B (...))' довольно неплохая идея, потому что вы не можете «переместить» объект 'const' ... Или еще лучше [pass-by-value] (http: // stackoverflow .com/questions/7592630/is-pass-by-value-a-rational-default-in-c11) 'A (B subb = B (" mmmmm "))' – WhiZTiM

ответ

1

Дело в том, что я построения 2 B классов, когда нужен только один ! И как-то, конструктор B вызывается только один раз, а деструктор называется дважды ... Что происходит ?!

Волшебства не происходит. Компилятор генерирует неявные копии и перемещает конструкторы. Чтобы получить истинную картину, Yours реализовать


class A{ 
public: 
    A(const B subb = B("mmmmm")): bclass(subb){ 
    cout << "A constructor." << endl; 
    } 

    ~A(){ 
    cout << "A destructor." << endl; 
    } 

private: 
    const B bclass; 
}; 

В конструкторе, B создается с помощью одного аргумента конструктора, затем назначенный subb, он копируется в bclass ... Так что на самом деле были Создано 3 экземпляра B.

  • Первый ваш Определяемый пользователем конструктор, поэтому вы видите ваш выход
  • Второй конструктор шаг используется для построения subb- компилятором по умолчанию
  • Третий является конструктор копирования используется для построения bclass- компилятор по умолчанию

Возможно, вы видели 2, потому что компилятор elided a call

+0

Спасибо за ваш ответ. Вы очистили меня от многих вещей. Теперь, что вы можете предложить, если мне нужен только один объект B, который нужно построить? – algolejos

+0

Я изменил класс A. Теперь 'bclass' - 'const B * bclass;' и изменил конструктор «A» на «A (B * subb = new B (« mmmmm »)): bclass (subb) {', и он отлично работает! – algolejos

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