Передача указателя объекта класса в функцию для инициализации C ++ - PullRequest
1 голос
/ 29 июля 2011

Допустим, у меня есть класс "А" и эта функция:

void initializationFunction(A* classPointer)
{
    ...
    ...
    classPointer = new A(.....); 
}

Я пишу:

A* classPointer;

Затем я передаю этот указатель этой функции:

initializationFunction(classPointer);

Это не будет работать, если я не передам его по ссылке в объявлении функции:

void initializationFunction(A*& classPointer);

Я думал, что передача ссылок была для переменных не указательного типа. Я имею в виду, вам не нужно передавать массив по ссылке ...

Спасибо за объяснения:)

Ответы [ 10 ]

5 голосов
/ 29 июля 2011

Да, это правда.Вы должны передать аргумент по ссылке (или вместо него можно передать A**).

Но лучшее решение - написать конструктор A таким образом, чтобы вам не понадобилась эта функцияна первом месте.То есть, что бы вы ни делали в этой функции, вы должны делать это в самом конструкторе.

Если, однако, вы не можете редактировать класс, вы можете сделать это вместо этого:

A *initializationFunction()
{
    A *obj = new A(.....); 
    //...
    return obj;
}

A *classPointer = initializationFunction();

На мой взгляд, этот подход лучше вашего.

Примечание. Я не менял имя функции и другие переменные.Я предполагаю, что это не главное в посте.Но я верю, что вам нужны более подходящие имена для реального кода.

1 голос
/ 29 июля 2011

говорят, что у вас есть ярлык Windows, указывающий на текстовый файл в «Мои документы».

Вы можете скопировать этот ярлык и вставить его в любое место окна, дважды щелкнуть по нему, и он откроет текстовый файл в «Мои документы». Это проходит по ссылке / указателю. Ярлык указывает на «где», затем вы используете его, чтобы изменить «материал».

Однако код, который вы разместили, не «открывает» файл, на который указывает ярлык. Это фактически изменяет ярлык, чтобы указать (фактически создать) новый «файл». Но поскольку сам ярлык был сначала скопирован (передан по значению), в результате вы выделяете память, но не можете получить к ней доступ. Таким же образом вы изменили ярлык, создали «файл», но затем удалили каталог с этим ярлыком (но ваш файл затем теряется в космосе!).

К сожалению, на самом деле не существует аналогии для передачи самого ярлыка по ссылке, вам, по сути, придется скопировать ярлык обратно из каталога, а затем заменить исходный текстовый файл в «моих документах» ярлыком на этот новый ». файл". Надеюсь, что это поможет, а не смущает дальше: (.

1 голос
/ 29 июля 2011

В вашем первом примере указатель передается по значению (т. Е. Функция получает копию указателя). Объект, на который указывает указатель, конечно же, одинаков как в вызывающем коде, так и внутри функции.

Во втором примере указатель передается по ссылке (т. Е. Функция в основном использует тот же указатель, что и вызывающий код).

1 голос
/ 29 июля 2011

Либо объявление со ссылкой, либо следующее:

void initializationFunction(A** classPointer);

Дело в том, что вы передаете аргумент-указатель и хотите изменить значение, которое оно имело в вызывающей стороне.Это параметр out , и параметры out должны передаваться по ссылке, а не по значению (здесь ссылка означает либо через указатель, либо через ссылку).Этот параметр out является указателем, поэтому вы должны передать указатель на этот указатель или ссылку на этот указатель.

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

void initializationFunction(A* classPointer);

classPointer сродни локальной переменной, определенной внутри initializationFunction, и является просто копией classPointer, выделенной в функции вызывающей стороны.Изменение копии classPointer не приведет к изменению исходной переменной, поэтому для ее изменения необходим указатель на исходную переменную.То же самое верно, если вы используете ссылку на оригинал classPointer.

Альтернативный подход, который у вас есть, это возврат нового classPointer из вашей функции:

    A* initializationFunction(void);

в этом случаевызывающий просто сделает:

A* classPointer = initializationFunction();
1 голос
/ 29 июля 2011

Либо используйте двойной указатель (**), либо ссылку, как вы это сделали.

1 голос
/ 29 июля 2011

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

0 голосов
/ 29 июля 2011

Это нормально.

Я объясняю:

void foo(X* toto)
{
  toto=new X();
}

значение будет выведено из стека вызовов с его начальным значением (как любой другой аргумент, указатель или нет), так как ононевозможно изменить значение аргумента функции, ЕСЛИ НЕ это ссылка.

так:

void foo(X*& toto)
{
 toto=new X();
}

Здесь вы явно указываете аргумент toto как X * & (X * для типа и & (ссылка) чтобы изменить его значение внутри функции foo)

Типы указателей такие же, как и у любых других типов.замените X * на int, и вы сразу обнаружите, что toto не будет изменено вне вызова функции, если не будет передано в качестве ссылки.

X ** также сделал бы уловку, используя такую ​​реализацию:

void foo(X** toto)
{
 *toto=new X();
}
0 голосов
/ 29 июля 2011

Вы можете передавать указатели по ссылке, потому что указатели также являются переменными со своим собственным адресом.Например, в 32-разрядной архитектуре вы можете объявить unsigned int и использовать его в качестве указателя.

0 голосов
/ 29 июля 2011

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

Когда вы делаете Aptr = new A(...), вы
- создаете 'A'объект где-то в куче
- присвоение адреса вновь созданного объекта Aptr

Если функция не имеет ссылки на Aptr, функция не может изменить свое значение.

0 голосов
/ 29 июля 2011

Должно быть:

void initializationFunction(A** classPointer)
{
    ...
    ...
    *classPointer = new A(.....); 
}

Вызов:

initializationFunction(&ptr);

функция установит аргумент, передаваемый в new A(......);

пример: http://ideone.com/u7z6W

...