Ошибка "request for member '...' in '...' which is of non-class type" в C++
Причина ошибки
Ошибка возникает из-за того, что ptr — это указатель на объект Student, а не сам объект. Когда вы пишете ptr.name, компилятор пытается найти поле name в типе Student* (указателе), а не в Student. Указатель — это не класс, у него нет членов, поэтому компилятор сообщает: "запрос члена у типа, не являющегося классом".
Решение: используйте оператор разыменования или стрелку
В C++ для доступа к членам объекта через указатель есть два способа:
1. Оператор разыменования * и точка .
Сначала разыменуйте указатель (получите сам объект), затем используйте точку:
(*ptr).name = "Ivan";
Скобки обязательны, потому что оператор точки имеет более высокий приоритет, чем оператор разыменования.
2. Оператор стрелки -> (рекомендуемый способ)
Это синтаксический сахар для предыдущего варианта. Стрелка делает то же самое — разыменовывает указатель и обращается к члену:
ptr->name = "Ivan";
Исправленный код
#include <iostream>
#include <string>
using namespace std;
class Student {
public:
string name;
int age;
void printInfo() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};
int main() {
Student* ptr = new Student();
// Правильный способ через стрелку
ptr->name = "Ivan";
ptr->age = 20;
// Или через разыменование: (*ptr).name = "Ivan";
ptr->printInfo(); // тоже через стрелку
delete ptr;
return 0;
}
Важное замечание: когда точка, а когда стрелка
- Точка (
.) — используется, когда у вас есть сам объект (не указатель):Student s; s.name = "Ivan"; - Стрелка (
->) — используется, когда у вас есть указатель на объект:Student* p = new Student(); p->name = "Ivan";
Дополнительный пример для закрепления
Student obj; // объект на стеке
obj.name = "Petr"; // точка
Student* pObj = &obj; // указатель на объект
pObj->name = "Petr"; // стрелка
// То же самое через разыменование:
(*pObj).name = "Petr"; // разыменование + точка
Запомните: если переменная объявлена как Тип* — используйте ->. Если как Тип — используйте .. Это универсальное правило для C++.
Альтернативный взгляд: работа с объектами на стеке
Если вы только начинаете изучать C++, часто проще избегать ручного управления памятью через new и delete. Вместо указателя можно создать объект непосредственно на стеке:
int main() {
Student student; // объект на стеке, не указатель
student.name = "Ivan";
student.age = 20;
student.printInfo();
// delete не нужен — объект уничтожится автоматически
return 0;
}
В этом случае вы используете точку (.) для доступа к членам, и ошибка не возникает. Такой подход проще для понимания и безопаснее — вы не рискуете забыть вызвать delete или получить утечку памяти.
Указатели с new стоит использовать, когда нужно динамическое выделение (например, для полиморфизма, массивов переменного размера или объектов, живущих дольше области видимости). Для учебных примеров на начальном этапе лучше обходиться стековыми объектами.