Последнее обновление:2026-10-12
Указатели на члены и информация о типах в C++¶
::* — полагаю, 99% людей никогда им не пользовались и даже не видели его; напишите об этом в комментариях! В этом разделе мы разберём синтаксис с нуля и применим этот приём на практике на примере из реального проекта.
1. Что такое ::*¶
C::* — это синтаксис указателя на член в C++, обозначающий указатель на член некоторого класса C. Этот синтаксис используется для указателей на переменные-члены или функции-члены класса. В отличие от обычных указателей, указатель на член не указывает на конкретный адрес памяти некоторого объекта, а указывает на позицию члена внутри класса, и использовать его нужно вместе с экземпляром объекта этого класса.
1.1 Синтаксис¶
T C::*— указатель на переменную-член типаTв классеC.R (C::*)(Args...)— указатель на функцию-член классаCс возвращаемым типомRи списком параметровArgs....
1.2 Указатель на переменную-член¶
Указатель на переменную-член указывает на переменную-член некоторого класса и записывается в форме T C::*.
Например: в примере ниже определён указатель на член ptr, который указывает на член x класса MyClass. Выражение obj.*ptr обращается к переменной-члену объекта через указатель на член.
struct MyClass {
int x;
double y;
};
int MyClass::*ptr = &MyClass::x;
MyClass obj;
obj.x = 10;
std::cout << "obj.x = " << obj.*ptr << std::endl;
1.3 Указатель на функцию-член¶
Указатель на функцию-член указывает на функцию-член класса и записывается в форме R (C::*)(Args...).
Пример: вызов функции-члена через obj.*funcPtr().
3. В чём польза?¶
Предположим, у вас есть ORM-фреймворк, которому нужно получить тип поля из указателя на член и сгенерировать тип соответствующего столбца. Это можно записать так:
struct User {
std::string username;
int user_id;
};
// 自动生成数据库列的定义
template <typename T, typename C>
void generate_sql_column(T C::*member_ptr, const std::string& column_name) {
if constexpr (std::is_same_v<T, std::string>) {
std::cout << column_name << " VARCHAR(255)" << std::endl;
} else if constexpr (std::is_integral_v<T>) {
std::cout << column_name << " INT" << std::endl;
}
}
int main() {
// 假设我们想自动为 User 类生成 SQL 表结构
generate_sql_column(&User::username, "username");
generate_sql_column(&User::user_id, "user_id");
return 0;
}
4. Практичный инструмент из реального проекта!¶
В реальном проекте мы можем извлекать тип объекта и тип члена с помощью C::*. Как это реализовать?
Ответ: шаблоны + C::*.
Как в примере ниже: с помощью value_type_from_member_pointer и class_type_from_member_pointer мы можем извлечь соответствующие тип члена и тип класса — очень удобный инструмент.
template <typename T, typename C>
struct from_member_pointer_helper<T C::*> {
using value_type = T;
using class_type = C;
};
template <auto Ptr>
struct from_member_pointer : from_member_pointer_helper<typename std::remove_cvref_t<decltype(Ptr)>> {};
template <auto Ptr>
using value_type_from_member_pointer = from_member_pointer<Ptr>::value_type;
template <auto Ptr>
using class_type_from_member_pointer = from_member_pointer<Ptr>::class_type;
Похожие темы¶
- Отказ от конструктора по умолчанию в C++ | C++那些事
- Идиома списков инициализации класса в C++ | C++那些事
- C++: классы-шаблоны вместо шаблонов функций | C++那些事
- Идиома copy-and-swap в C++ | C++那些事
- Внедрение зависимостей в C++ | C++那些事
- Сильнотипизированные перечисления enum class в C++ | C++那些事
- Header-Only в C++ против разделения реализации | C++那些事
- Идиома ленивых вычислений в C++ | C++那些事
- Идиома таблиц поиска в C++ | C++那些事
- Идиома Mixin в C++ | C++那些事