С++. Классы. Виртуальное наследование. Проектирование классов
Имеется родительский класс A, в котором объединены различные функции и другие классы, как члены данного класса (в примере это поинтер класса D). Далее я создаю класс A_Object, данный класс будут наследовать другие классы, чтобы они могли использовать функции класса A. Так как мне нужно, чтобы класс A создавался единожды (соотвественно и не повторялось создание класса D), я использую виртуальное наследование. Любые другие классы, например, B и C, уже будут наследовать класс A_Object, таким образом я единожды создаю класс A и использую его функции через наследование класса A_Object. Построение классов начинается с класса A, но почему-то вызывается его пустой конструктор (хотя насколько я понял, должен вызываться конкретно конструктор с аргументом, т.к. при создании класса B я передаю этот аргумент). Как итог программа завершает работу неправильно. Скорее всего, я изначально неправильно проектирую построение классов. Поэтому прошу помочь либо с корректировкой моего примера либо с проектировкой нового.
/*
result:
init B
A()
A_Object(std::string auth): auth-token
D(std::string auth):
B(std::string auth): auth-token
D::print():
init C
A()
A_Object()
C()
D::print():
test.exe (процесс 9168) завершил работу с кодом -1073741819.
*/
class D
{
std::string m_auth;
public:
D(std::string auth) :
m_auth(auth)
{
std::cout << "D(std::string auth): " << auth << std::endl;
}
void print()
{
std::cout << "D::print(): " << m_auth << std::endl;
}
};
class A
{
D* m_class_d;
std::string m_auth;
public:
A() :
m_class_d(nullptr)
{
std::cout << "A()" << std::endl;
}
A(std::string auth) :
m_class_d(nullptr),
m_auth(auth)
{
std::cout << "A(std::string auth): " << auth << std::endl;
}
~A()
{
delete m_class_d;
}
void create()
{
m_class_d = new D(m_auth);
}
D* get_class_d()
{
return m_class_d;
}
std::string get_auth()
{
return m_auth;
}
};
class A_Object : virtual public A
{
public:
A_Object()
{
std::cout << "A_Object()" << std::endl;
}
A_Object(std::string auth) :
A(auth)
{
std::cout << "A_Object(std::string auth): " << auth << std::endl;
create();
}
};
class B : public A_Object
{
public:
B(std::string auth) :
A_Object(auth)
{
std::cout << "B(std::string auth): " << auth << std::endl;
}
};
class C : public A_Object
{
public:
C()
{
std::cout << "C()" << std::endl;
}
};
int main()
{
std::cout << "init B" << std::endl;
B b("auth-token");
b.get_class_d()->print();
std::cout << "init C" << std::endl;
C c;
c.get_class_d()->print();
return 0;
}```
Ответы (1 шт):
Чтобы было понятней, давайте упростим код:
class A
{
public:
A()
{
std::cout << "A()" << std::endl;
}
A(const std::string& auth)
{
std::cout << "A(std::string auth): "<< std::endl;
}
};
class A_Object : virtual public A
{
public:
A_Object()
{
std::cout << "A_Object()" << std::endl;
}
A_Object(const std::string& auth) :
A(auth)
{
std::cout << "A_Object(std::string auth): " << auth << std::endl;
}
};
class B : public A_Object
{
public:
B(const std::string& auth) :
A_Object(auth)
{
std::cout << "B(std::string auth): " << auth << std::endl;
}
};
Для A_Object a будет вызываться конструктор по умолчанию базового класса, до конструирования объекта . Результат:
A()
A_Object()
Для B b("auth-token") Будет вызываться в первую очередь конструктор базового класса, на чем строится объект b, а значит конструктор A(). Что выводит на экран:
A()
Так как в списке инициализатора конструктора целевого объекта нет этого конструктора, а есть только конструктор A_Object, который в свою очередь вызвал бы конструктор своего базового класса, если бы он не был виртуальным, а с учетом виртуальности, у него уже есть базовый объект, который создан конструктором класса B а значит будет выведен только:
A_Object(std::string auth): auth-token
B(std::string auth): auth-token
Для того, чтобы объект целевого производного класса строился на объекте виртуального класса, созданным посредством вызова нужного конструктора, нужно в инициализаторе целевого класса, указать явно:
B::B(const std::string& auth) : A(auth),
A_Object(auth) {... }
Тогда и получите результат с вызовом конструктора виртуального базового класса А с аргументом.