Я нуждаюсь:
Создать ссылку на объект.
Передайте его функции, которая вызывает конструктор класса объекта и выполняет некоторые вычисления над объектом.
Передайте объект другой функции, которая также сделает с ним что-то.
Мой объект, который переходит ко второй функции, всегда пуст.
Я немного знаю разницу между памятью стека и кучи и использованием оператора new, но не могу с этим справиться. Я не понимаю, почему g
не меняется после окончания func1.
#include <iostream>
class Grid
{
public:
int a;
Grid()
{
a = 2;
}
};
void func1(Grid * g);
void func2(Grid * g);
int
main ()
{
Grid g;
func1(&g);
func2(&g);
}
void
func1 (Grid * g)
{
g = new Grid();
g->a = 5;
}
void
func2 (Grid * g)
{
std::cout << g->a << std::endl;
}
Как сделать вывод в func2 5, потому что сейчас 2?
Спасибо! Почему этот указатель временный? и как с этим бороться?
Он временный, как и любой другой параметр функции, независимо от того, является ли он указателем на значение.
@vahancho: слово «временный» здесь не совсем точно. Это "местное". Также указатель является значение!
@vahancho Также, пожалуйста, не отвечайте в разделе комментариев
Если вы хотите использовать указатели для «передачи по ссылке», просто сделайте это:
void
func1 (Grid * g)
{
g->a = 5;
}
void
func2 (const Grid * g)
{
std::cout << g->a << std::endl;
}
int
main ()
{
Grid g;
func1(&g);
func2(&g);
}
В настоящее время вы берете указатель (и помните, что сам указатель передается по значению), затем перезапись копия этого указателя в локальной области с указателем на новый динамически выделяемый объект Grid
. Вы устанавливаете свойство для этого объекта, а затем пропускаете его.
В C++ вместо этого мы часто используем фактические ссылки, которые могут быть более понятными (хотя, возможно, не такими понятными на сайте вызова!):
void
func1 (Grid& g)
{
g.a = 5;
}
void
func2 (const Grid& g)
{
std::cout << g.a << std::endl;
}
int
main ()
{
Grid g;
func1(g);
func2(g);
}
Что касается этого бита:
Pass it to a function that calls the constructor of the object's class
Объект уже построен. Вы можете скопировать-назначить из нового временного объекта, если вы действительно хотите «сбросить» его таким образом:
void
func1 (Grid& g)
{
g = Grid();
g.a = 5;
}
Но я бы посоветовал пересмотреть, действительно ли вы хотите/нужно сбрасывать объект таким образом. И, если вы это сделаете, может быть, хорошая функция-член reset()
?
Вы не компилируете
@SombreroChicken Твоя мама тоже
Но ее домашнее печенье очень вкусное.
@SombreroChicken Biscuits!
Такая же разница. Цвет цветвкус вкус плавать плавать плавать мама мама ПОМОГИТЕ
Хорошо, поэтому я хочу извиниться, это произошло не из-за вашего кода, но я думаю, что микрочип моего рабочего стола неисправен.
@SombreroChicken Classic ?
Но что, если я получу результаты для конструктора только внутри func1? То есть я могу избежать создания объекта внутри func1?
@SergeiShumilin Вы можете дать своему классу функцию-член reset()
.
На самом деле, когда вы используете new
, вы меняете значение указателя.
Но в любом случае, я думаю, вы можете сделать это намного проще. Например:
void func(Grid & g)
{
g.a = 5;
}
Обновлено:
Конечно, вы должны вызывать func()
так:
Grid gr;
func(gr);
Я надеюсь, что это может помочь;
Вы имели в виду инициализировать объект здесь? Нравится Grid{}
?
Но что, если я получу результаты для конструктора только внутри func1? То есть я могу избежать создания объекта внутри func1?
@SergeiShumilin Когда вы объявляете Grid g;
, вы вызываете конструктор по умолчанию. Так что вам не нужно вызывать конструктор внутри func1()
. Но если вы хотите сбросить его, вы можете либо вызвать g = Grid();
внутри func1()
, либо создать функцию-член reset()
, как вам посоветовал @LightnessRacesInOrbit.
Чтобы помочь вам представить это, я напишу это так:
#include <iostream>
class Grid
{
public:
int a;
Grid()
{
a = 2;
}
};
void func1(uint64_t g);
void func2(uint64_t g);
int
main ()
{
Grid g;
func1((uint64_t)&g);
func2((uint64_t)&g);
}
void
func1 (uint64_t g)
{
g = (uint64_t)new Grid();
((Grid*)g)->a = 5;
}
void
func2 (uint64_t g)
{
std::cout << ((Grid*)g)->a << std::endl;
}
Приведенный выше код будет работать точно так же, как и другой код (в 64-битной системе). Очевидно, что это ужасно, и приведенный выше код никогда не следует использовать, но написание его таким образом может помочь вам понять указатели.
Я не думаю, что приведение всего к uint64_t
— хороший способ понять указатели.
Я не знаю, это демонстрирует, что указатели - это просто числа, как и любая другая переменная.
Но это не так.
Да, указатель - это число. Так получилось, что это число является адресом памяти другой переменной, но по сути это все еще число.
Нет, это в основном указатель. То, что они могут быть представлены в виде чисел, является либо деталью реализации, либо утечкой абстракции, в зависимости от того, как вы на это смотрите. Но указатели гораздо более ограничены, чем числа. (Правда, по какой-то причине это малоизвестно.) Указатели — это не числа; они указатели.
вот еще одна возможность использования указателей
Grid * func1();
void func2(Grid * g);
int main ()
{
Grid * g = func1();
func2(g);
}
Grid * func1 ()
{
Grid * g = new Grid();
g->a = 5;
return g;
}
void func2 (Grid * g)
{
std::cout << g->a << std::endl;
}
Объясните свое решение. Также у вас есть утечка памяти.
нужно просто удалить указатель в конце программы конечно, и добавить некоторую защиту при выделении памяти. но версия, использующая ссылку, по-прежнему лучшее решение, я думаю.
Этот
g = new Grid();
изменяет временный указательg
, а не исходный объект. Вот почему значениеGrid::a
остается неизменным. Что если убрать это утверждение:g = new Grid();
?