У меня есть класс, который имеет несколько объектов в качестве переменных-членов. Я не хочу, чтобы конструкторы для этих членов вызывались при объявлении, поэтому я пытаюсь явно указать указатель на объект. Я не имею понятия что я делаю. о_О
В StackOverflow я, кажется, смог найти другие примеры переменных-членов объекта, но обычно конструктор вызывается немедленно, например так:
class MyClass {
public:
MyClass(int n);
private:
AnotherClass another(100); // this constructs AnotherClass right away!
};
Но я хочу MyClass
конструктор для вызова AnotherClass
конструктор. Вот как выглядит мой код:
BigMommaClass.h
#include "ThingOne.h"#include "ThingTwo.h"
class BigMommaClass {
public:
BigMommaClass(int numba1, int numba2);
private:
ThingOne* ThingOne;
ThingTwo* ThingTwo;
};
BigMommaClass.cpp
#include "BigMommaClass.h"
BigMommaClass::BigMommaClass(int numba1, int numba2) {
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
}
Вот ошибка, которую я получаю, когда пытаюсь скомпилировать:
g++ -Wall -c -Iclasses -o objects/BigMommaClass.o classes/BigMommaClass.cpp
In file included from classes/BigMommaClass.cpp:1:0:
classes/BigMommaClass.h:12:8: error: declaration of âThingTwo* BigMommaClass::ThingTwoâ
classes/ThingTwo.h:1:11: error: changes meaning of âThingTwoâ from âclass ThingTwoâ
classes/BigMommaClass.cpp: In constructor âBigMommaClass::BigMommaClass(int, int)â:
classes/BigMommaClass.cpp:4:30: error: cannot convert âThingOneâ to âThingOne*â in assignment
classes/BigMommaClass.cpp:5:37: error: â((BigMommaClass*)this)->BigMommaClass::ThingTwoâ cannot be used as a function
make: *** [BigMommaClass.o] Error 1
Я использую правильный подход, но неправильный синтаксис? Или я должен прийти к этому с другой стороны?
Вы можете указать, как инициализировать элементы в списке инициализаторов:
BigMommaClass {
BigMommaClass(int, int);
private:
ThingOne thingOne;
ThingTwo thingTwo;
};
BigMommaClass::BigMommaClass(int numba1, int numba2)
: thingOne(numba1 + numba2), thingTwo(numba1, numba2) {}
Вы пытаетесь создать ThingOne
используя operator=
который не будет работать (неправильный синтаксис). Кроме того, вы используете имя класса в качестве имени переменной, то есть ThingOne* ThingOne
, Во-первых, давайте исправим имена переменных:
private:
ThingOne* t1;
ThingTwo* t2;
Поскольку это указатели, они должны на что-то указывать. Если объект еще не был построен, вам нужно сделать это явно с новым в вашем BigMommaClass
конструктор:
BigMommaClass::BigMommaClass(int n1, int n2)
{
t1 = new ThingOne(100);
t2 = new ThingTwo(n1, n2);
}
Обычно списки инициализаторов предпочтительнее для построения, поэтому он будет выглядеть так:
BigMommaClass::BigMommaClass(int n1, int n2)
: t1(new ThingOne(100)), t2(new ThingTwo(n1, n2))
{ }
Этот вопрос немного устарел, но в c ++ 11 есть еще один способ «сделать больше работы» в конструкторе перед инициализацией переменных-членов:
BigMommaClass::BigMommaClass(int numba1, int numba2)
: thingOne([](int n1, int n2){return n1+n2;}(numba1,numba2),
thingTwo(numba1, numba2) {}
Вышеприведенная лямбда-функция будет вызвана, а результат передан конструктору thingOnes. Конечно, вы можете сделать лямбду настолько сложной, насколько захотите.
Я знаю, что это 5 лет спустя, но в приведенных выше ответах не говорится о том, что не так с вашим программным обеспечением. (Ну, Юши делает, но я не понял, пока не набрал это — дох!). Они отвечают на вопрос в заголовке Как я могу инициализировать переменные-члены объекта C ++ в конструкторе? Это о других вопросах: Я использую правильный подход, но неправильный синтаксис? Или я должен прийти к этому с другой стороны?
Стиль программирования в значительной степени зависит от мнения, но альтернативное представление о том, как сделать в конструкторе как можно больше, заключается в том, чтобы свести конструкторов к минимуму, часто имея отдельную функцию инициализации. Нет необходимости пытаться втиснуть всю инициализацию в конструктор, не говоря уже о том, чтобы время от времени пытаться принудительно вводить вещи в список инициализации конструкторов.
Итак, что же случилось с вашим программным обеспечением?
private:
ThingOne* ThingOne;
ThingTwo* ThingTwo;
Обратите внимание, что после этих строк ThingOne
(а также ThingTwo
) теперь имеют два значения, в зависимости от контекста.
Вне BigMommaClass, ThingOne
это класс, который вы создали с #include "ThingOne.h"
Внутри BigMommaClass, ThingOne
это указатель
Это предполагает, что компилятор может даже понимать строки и не зацикливаться на мысли, что ThingOne
это указатель на что-то, что само по себе является указателем на что-то, что является указателем на …
Позже, когда ты пишешь
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
имейте в виду, что внутри BigMommaClass
ваш ThingOne
это указатель
Если вы измените объявления указателей, чтобы включить префикс (p)
private:
ThingOne* pThingOne;
ThingTwo* pThingTwo;
затем ThingOne
всегда будет относиться к классу и pThingOne
к указателю.
Тогда можно переписать
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
как
pThingOne = new ThingOne(100);
pThingTwo = new ThingTwo(numba1, numba2);
которая исправляет две проблемы: проблему двойного значения и отсутствие new
, (Ты можешь уйти this->
если хочешь!)
Имея это в виду, я могу добавить следующие строки в мою программу на c ++, и она прекрасно компилируется.
class ThingOne{public:ThingOne(int n){};};
class ThingTwo{public:ThingTwo(int x, int y){};};
class BigMommaClass {
public:
BigMommaClass(int numba1, int numba2);
private:
ThingOne* pThingOne;
ThingTwo* pThingTwo;
};
BigMommaClass::BigMommaClass(int numba1, int numba2)
{
pThingOne = new ThingOne(numba1 + numba2);
pThingTwo = new ThingTwo(numba1, numba2);
};
Когда ты написал
this->ThingOne = ThingOne(100);
this->ThingTwo = ThingTwo(numba1, numba2);
использование this->
сообщает компилятору, что левая сторона ThingOne
предназначен для обозначения указателя. Однако мы внутри BigMommaClass
в то время и в этом нет необходимости.
Проблема с правой стороны равных где ThingOne
предназначен для обозначения класса. Так что другим способом исправить ваши проблемы было бы написать
this->ThingOne = new ::ThingOne(100);
this->ThingTwo = new ::ThingTwo(numba1, numba2);
или просто
ThingOne = new ::ThingOne(100);
ThingTwo = new ::ThingTwo(numba1, numba2);
с помощью ::
изменить интерпретацию идентификатора компилятором.
Я (также, как и другие упоминали) осознает тот факт, что этот вопрос старый, но я хотел бы указать кое-что относительно первого (и отлично) ответ от @Крис кто предложил решение ситуации, когда ученики содержатся внастоящий композит«члены (т.е. НЕ как указатели NOR Рекомендации).
Примечание немного большое, поэтому я продемонстрирую его здесь с примером кода.
Когда вы решили держать членов, как я уже упоминал, вы должны иметь в виду и эти две вещи:
1) Для каждого «составного объекта», который НЕ есть ctor по умолчанию — вы ДОЛЖЕН инициализировать его в списке инициализации ВСЕ Которы класса «отец» (т.е. BigMommaClass
или же MyClass
в исходных примерах и MyClass
в приведенном ниже коде), если их несколько (см. InnerClass1
в приведенном ниже примере). Это означает, что вы можете «закомментировать» m_innerClass1(a)
а также m_innerClass1(15)
ТОЛЬКО если вы включите InnerClass1
ctor по умолчанию.
2) Для каждого «составного объекта», который Имеет ctor по умолчанию — вы МОЖЕТ инициализируйте его в списке инициализации, но он также будет работать, если вы решили этого не делать (см. InnerClass2
в приведенном ниже примере).
Смотрите пример кода (соблюдается в Ubuntu 18.04 с g++
версия 7.3.0):
#include <iostream>
using namespace std;
class InnerClass1
{
public:
InnerClass1(int a) : m_a(a)
{
cout << "InnerClass1::InnerClass1 - set m_a:" << m_a << endl;
}
/* No default cotr
InnerClass1() : m_a(15)
{
cout << "InnerClass1::InnerClass1() - set m_a:" << m_a << endl;
}
*/
~InnerClass1()
{
cout << "InnerClass1::~InnerClass1" << endl;
}
private:
int m_a;
};
class InnerClass2
{
public:
InnerClass2(int a) : m_a(a)
{
cout << "InnerClass2::InnerClass2 - set m_a:" << m_a << endl;
}
InnerClass2() : m_a(15)
{
cout << "InnerClass2::InnerClass2() - set m_a:" << m_a << endl;
}
~InnerClass2()
{
cout << "InnerClass2::~InnerClass2" << endl;
}
private:
int m_a;
};
class MyClass
{
public:
MyClass(int a, int b) : m_innerClass1(a), /* m_innerClass2(a),*/ m_b(b)
{
cout << "MyClass::MyClass(int b) - set m_b to:" << m_b << endl;
}
MyClass() : m_innerClass1(15), /*m_innerClass2(15),*/ m_b(17)
{
cout << "MyClass::MyClass() - m_b:" << m_b << endl;
}
~MyClass()
{
cout << "MyClass::~MyClass" << endl;
}
private:
InnerClass1 m_innerClass1;
InnerClass2 m_innerClass2;
int m_b;
};
int main(int argc, char** argv)
{
cout << "main - start" << endl;
MyClass obj;
cout << "main - end" << endl;
return 0;
}