Última atualização:2026-10-12
Ponteiros para membros e type info em C++¶
::* — provavelmente 99% das pessoas nunca usaram, nem sequer viram; podem dizer isso na área de comentários! Esta seção explica a sintaxe do zero e usa um exemplo real de projeto para praticar esse uso.
1. O que é ::*¶
C::* é a sintaxe de ponteiro para membro em C++, representando um ponteiro para um membro de uma classe C. Essa sintaxe serve para apontar para variáveis-membro ou funções-membro da classe. Diferente dos ponteiros comuns, um ponteiro para membro não aponta para um endereço de memória concreto de um objeto, mas para a posição do membro na classe, e precisa ser usado junto com uma instância de objeto da classe.
1.1 Sintaxe¶
T C::*é um ponteiro para uma variável-membro de tipoTna classeC.R (C::*)(Args...)é um ponteiro para uma função-membro da classeCcom tipo de retornoRe lista de argumentosArgs....
1.2 Ponteiro para variável-membro¶
O ponteiro para variável-membro aponta para uma variável-membro de determinada classe, usando a forma T C::*.
Por exemplo: no exemplo abaixo é definido um ponteiro para membro ptr, que aponta para o membro x da classe MyClass. obj.*ptr acessa a variável-membro do objeto por meio do ponteiro para membro.
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 Ponteiro para função-membro¶
O ponteiro para função-membro aponta para uma função-membro da classe, usando a forma R (C::*)(Args...).
Exemplo: chamando a função-membro por meio de obj.*funcPtr().
3. Para que serve?¶
Suponha que você tenha um framework ORM e precise obter, a partir do ponteiro para membro, o tipo do campo para gerar o tipo da coluna correspondente; pode-se escrever assim:
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. Utilitários práticos derivados em projetos reais!¶
Em projetos reais, podemos usar C::* para extrair o tipo do objeto e o tipo do membro; como implementar?
Resposta: templates + C::*
Como no exemplo abaixo, por meio de value_type_from_member_pointer e class_type_from_member_pointer extraímos o tipo do membro e o tipo da classe correspondentes — uma ferramenta muito conveniente.
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;
Tópicos relacionados¶
- C++ evitar o construtor padrão | C++那些事
- Idiom de lista de inicialização de classes em C++ | C++那些事
- C++: templates de classe em vez de templates de função | C++那些事
- Idiom copy-and-swap em C++ | C++那些事
- Injeção de dependência em C++ | C++那些事
- C++ enum class enumerações fortemente tipadas | C++那些事
- C++ Header-Only versus separação de implementação | C++那些事
- Idiom de avaliação preguiçosa em C++ | C++那些事
- Idiom de consulta em tabela em C++ | C++那些事
- Idiom Mixin em C++ | C++那些事