C ++: 62 --- herramientas y técnicas especiales como puntero miembro (adicional: exigible, plantilla mem_fn)

  • visión general del puntero de usuario:
    • Esto significa que el puntero miembro de puntero puede apuntar a un miembro no estático de la clase
    • En circunstancias normales, un puntero a un objeto, pero los miembros del puntero es un miembro de la clase, no a la clase de objeto creado a partir
    • miembros de la clase estática no pertenecen a ningún objeto, y por lo tanto hay puntos especiales puntero del miembro estático a un puntero a un miembro estático sin diferencia entre un puntero ordinario
    • miembros de tipo incluyen el tipo de miembros de tipo puntero y clase:
      • Al inicializar un puntero a esto, que sea un punto a los miembros de la clase, pero el objeto no se especifica, el miembro pertenece
      • Hasta que el uso de puntero de estos, solamente proporcionar a los miembros de objetos pertenecen
  • Aquí definimos una clase, ya que el documento sobre la base de:
class Screen {
public:
    typedef std::string::size_type pos;

    char get_cursor()const { return contents[cursor]; }
    char get()const;
    char get(pos ht, pos wd)const;
private:
    std::string contents;
    pos cursor;
    pos height, width;
};

En primer lugar, el puntero del miembro de datos

Definir el puntero del miembro de datos

  • características:
    • Necesitamos * para indicar la variable actual es un puntero
    • Al definir puntero del miembro debe incluir la clase pertenece
  • Definir el puntero
    • La siguiente definición de un puntero al objeto de pantalla, un puntero de tipo cadena, el puntero y el puntero es constante (y por lo tanto no puede ser modificado por el valor del puntero)
    • Dado que el tipo de la cadena del indicador, de manera que el puntero puede apuntar a un miembro de cadena constante (const) objeto Screen
const string Screen::*pdata;
  • asignación de puntero:
//将pdata指向于Screen类的contents成员
pdata = &Screen::contents;
  • Se puede inicializarse directamente en la definición de miembro de datos de puntero , y el auto o decltype define:
auto pdata = &Screen::contents;

Usando el puntero del miembro de datos

  • Una vez definido el puntero , el puntero no apunta a ningún miembro de datos , solamente un puntero a punto de un objeto pertenece a los miembros y no sólo cuando un puntero miembro de eliminar la referencia que proporciona información sobre el objeto
  • Por ejemplo:
Screen myScreen;
Screen *pScreen = &myScreen;

//.*解引用*pdata以获得myScreen对象的contents成员
auto s = myScreen.*pdata; //相当于myScreen.contents

//->*解引用*pdata以获得myScreen对象的contents成员
s = pScreen->*pdata;      //相当于pScreen->contents

Devoluciones funciones miembro datos de puntero

  • Cuando un puntero miembro se ha definido anteriormente, pData no aparece en el exterior de la clase Screen, ya que el contenido de un privado (sólo para demostrar la descripción anterior)
  • Con el fin de reflejar la encapsulación, por lo general nos definimos una función miembro, la función devuelve un puntero a un miembro de la
  • Por ejemplo:
class Screen {
public:
    //成员函数,返回一个成员的指针
    static const std::string Screen::*data() { 
        return &Screen::contents; 
    }
private:
    std::string contents;
};
  • Vamos a función se define como estática, que no pertenece a ningún objeto, por lo que podemos llamar a esta función directamente para el indicador del número de miembros
  • Cuando llamamos a los datos, se puede obtener un puntero a un miembro. Por ejemplo:
int main()
{
    //调用data()静态函数来获得一个成员的指针
    const std::string Screen::*pdata = Screen::data();
    return 0;
}
  • Una vez definido, podemos usar el puntero normal. Por ejemplo:
int main()
{
    Screen *pScreen = new Screen;

    const std::string Screen::*pdata = Screen::data();
    auto s = pScreen->*pdata; //等价于pScreen->contents

    return 0;
}

En segundo lugar, los punteros de función miembro

  • Y un puntero que apunta al miembro de datos similar, podemos declarar un puntero a un puntero a una función miembro
  • Nota sintaxis:
    • Los punteros a funciones miembro también requieren tipo de orientación retorno de la función y la lista de parámetros
    • Si método constante, o una referencia a un miembro, entonces debemos ser calificadores calificador const incluyen o se hace referencia a venir

La definición de los punteros de función miembro

  • La forma más sencilla es utilizar automóviles para declarar un puntero a un puntero a una función miembro
//pmf是一个函数指针,指向于get_cursor函数
auto pmf = &Screen::get_cursor;
  • Debido a que la definición de los punteros de función miembro, es necesario especificar la lista de funciones objetivo y el tipo de retorno de parámetros , y por lo tanto al haber sobrecargado función miembro no causa conflicto. Por ejemplo:
class Screen {
public:
    typedef std::string::size_type pos;

    char get_cursor()const { return contents[cursor]; }
    char get()const;
    char get(pos ht, pos wd)const;
    //...
};

int main()
{
    //pmf2是一个成员函数指针,其指向于返回值为char,形参为两个Screen::pos类型的成员函数
    char (Screen::*pmf2)(Screen::pos, Screen::pos)const;
    //为pmf2指针赋值
    pmf2 = &Screen::get;
    return 0;
}
  • Para consideración prioritaria, soportes en ambos lados del puntero de las definiciones anteriores no faltan . Sin este par de paréntesis, el compilador va a pensar que es una declaración (válido) declaración de la función:
    • Error: compilador pensará que p es una función normal, y devuelve un miembro de carbón de la clase Screen. Debido a que es una función normal, por lo que no se puede utilizar calificador const
//错误的语法,非成员函数p不能使用const限定符
char Screen::*pmf2(Screen::pos, Screen::pos)const;
  • punteros a funciones ordinarias que no existe regla de conversión automática entre el miembro y el puntero a los miembros de función:
char (Screen::*pmf2)(Screen::pos, Screen::pos)const;

pmf2 = &Screen::get; //正确
pmf2 = Screen::get;  //错误,缺少&。在成员函数和指针之间不存在自动转换规则

punteros de función miembro

  • Y el uso de los miembros de datos de puntero, tenemos que utilizar el * o -> * puntero de ámbito de operador para una función miembro para llamar a las funciones miembro de clase
  • Por ejemplo:
//pmf为成员函数指针,指向于get_cursor()函数
auto pmf = &Screen::get_cursor;
//pmf2为成员函数指针,指向于带有两个参数的get()函数
char (Screen::*pmf2)(Screen::pos, Screen::pos)const = &Screen::get;

Screen myScreen;
Screen *pScreen = &myScreen;

char c1 = (myScreen.*pmf)();     //等价于myScreen.get_cursor()
char c2 = (pScreen->*pmf2)(0, 0);//等价于pScreen->get(0,0)
  • En lo anterior, la necesidad de añadir soportes en ambos lados cuando eliminación de referencias a punteros a funciones miembro, si no, sería un error:
    • Las razones equivocadas: que quieren llamar a un PMF y PMF2 función llamada, y luego usar el valor de retorno de estas funciones como un puntero a miembro de operador * y -> * Cálculo pensar. Sin embargo PMF con PMF2 no es una función, por lo que el código de error
char c1 = myScreen.*pmf();      //错误的
//其等价于myScreen.*(pmf())

char c2 = pScreen->*pmf2(0, 0); //错误的
//其等价于myScreen->*(pmf2(0,0))

El uso del puntero del miembro del tipo de alias

  • Utilizar un alias o escriba typedef permite a los miembros del puntero más fácil de entender
  • Por ejemplo, el siguiente tipo de alias parámetro Action se define como un sinónimo para obtener dos funciones:
//Action是一种可以指向Screen成员函数的指针,其接受两个pos实参,返回值类型为char
using Action = char (Screen::*)(Screen::pos, Screen::pos)const;
  • Ahora nos definimos un puntero a función miembro cuando es más conveniente:
//get是一个指向成员函数的指针
Action get = &Screen::get;
  • Y otra puntero de función similar, que puede ser un puntero a una función miembro como un tipo de retorno de la función o el tipo de parámetro . En el que un puntero a miembro de parámetro también puede tener un argumento predeterminado
using Action = char (Screen::*)(Screen::pos, Screen::pos)const;

//action是一个函数,其中参数2为一个指针,并且其有默认实参,指向于Screen的get成员函数
Screen& action(Screen&, Action = &Screen::get);
  • Cuando llamamos a la función de acción, solamente un puntero o dirección de una función a cumplir los requisitos de la pantalla de entrada a:
using Action = char (Screen::*)(Screen::pos, Screen::pos)const;
Screen& action(Screen&, Action = &Screen::get);

int main()
{
    Screen myScreen;
    Action get = &Screen::get;

    action(myScreen);               //使用默认实参
    action(myScreen, get);          //参数2调用前面定义的指针变量get
    action(myScreen, &Screen::get); //参数2显式地传入地址
    return 0;
}

Miembro tabla de punteros de función

  • Para los punteros a funciones ordinarias y punteros a funciones miembro, el uso común es almacenar en una tabla de funciones
  • Si una clase contiene varios miembros del mismo tipo, a continuación, una tabla de este tipo nos puede ayudar a elegir uno de estos miembros
  • clase Screen contiene varias funciones miembro asumido, cada función es responsable de mover el cursor en la dirección especificada:
class Screen {
public:
    typedef std::string::size_type pos;
	
    //移动光标的一系列函数
    Screen& home();
    Screen& forward();
    Screen& back();
    Screen& up();
    Screen& down();
private:
    pos cursor; //光标
};
  • Estas funciones tienen en común: no acepta ningún parámetro y el valor de retorno es una referencia a la ocurrencia de movimiento del cursor de la pantalla
  • Ahora comenzamos la tabla de funciones de diseño:
    • Antes de esto, definir primero un Menú miembro estático, el miembro es una matriz de punteros a las funciones de movimiento de cursor
    • Una función de movimiento se define, puede llamar a cualquier función anterior y realizar una operación correspondiente
    • Una función de enumeración diseñado para la participación de las masas
class Screen {
public:
    typedef std::string::size_type pos;
	
    Screen& home();
    Screen& forward();
    Screen& back();
    Screen& up();
    Screen& down();

    //函数指针
    using Action = Screen& (Screen::*)();

    //定义一个枚举
    enum Directions { HOME, FORWARD, BACK, UP, DOWN };
    //参数使用枚举来调用函数表中对应的函数
    Screen& move(Directions cm)
    {
        //必须使用this
        return (this->*Menu[cm])();
    }
private:
    pos cursor;

    static Action Menu[]; //函数表
};

//初始化函数表,将内部移动光标的函数都添加进去
Screen::Action Screen::Menu[] = {
    &Screen::home,&Screen::forward,
    &Screen::back,&Screen::up,
    &Screen::down };
  • Ahora podemos llamar a la función de movimiento:
int main()
{
    Screen myScreen;
    myScreen.move(Screen::HOME); //调用muScreen.home
    myScreen.move(Screen::DOWN); //调用muScreen.down

    return 0;
}

En tercer lugar, la función de miembro como un objeto invocable

Los miembros de los punteros no son exigible

  • A través de lo anterior sabemos, desea llamar el puntero de función miembro, debe cumplir por una clase o de operador * -> * operador de llamada. Por lo tanto punteros a funciones ordinarias, el puntero no es miembro de un exigible , un puntero tal no admite el operador de llamada de función (el operador llamada a la función ver la lambda: https://blog.csdn.net/qq_41453285/article/details/96118675 )
  • Dado que los miembros de los punteros son no exigible, por lo que no puede ser directamente un puntero a una función miembro pasa al algoritmo
  • Por ejemplo, el siguiente en primer lugar encontrar una cadena vacía en un vector en el que:
std::vector<std::string> svec;
auto fp = &std::string::empty; //fp指向string的empty函数,fp是一个成员函数指针

//错误,必须使用.*或->*调用成员指针fp
std::find_if(svec.begin(), svec.end(), fp);
  • find_if algoritmo requiere un objeto invocable , pero siempre a que es un puntero a un puntero de función fp miembro. De este modo realiza la forma de código fuente dentro de la find_if, dando lugar a que no se compile:
//检查对当前元素的断言是否为真
if(fp(*it))  //错误,想要通过成员指针调用函数,必须使用->*运算符
  • La afirmación aparentemente tratando de llamada entrante es objeto, no una función

① función de uso para generar un objeto invocable

std::vector<std::string> svec;
	
//empty函数的返回值为bool,参数为const string&
function<bool(const std::string&)> fcn = &std::string::empty;

//现在是正确的了,fcn是一个可调用对象,使用.*调用empty
std::find_if(svec.begin(), svec.end(), fcn);
  • Cuando un objeto de función contiene un puntero que apunta a la función miembro, M clase unción sabe que debe utilizar el puntero correcto operador miembro para realizar una llamada a la función . En otras palabras, podemos decir que no es similar al código siguiente dentro de find_if:
//假设it是find_if内部的迭代器,则*it是一个string对象
if(fcn(*it)) //fcn就是empty的函数指针,等价于empty(*it)
  • En donde, la función utiliza el puntero correcto operador miembro. En esencia, la función basada en una llamada a la función de la forma siguiente:
if(((*it).*p)) //假设p是fcn内部的一个指向成员函数的指针,此案例中为指向于empty函数的指针
  • El código siguiente llama los principios anteriores son similares
std::vector<std::string*> svec;

//empty函数的返回值为bool,参数为const string*	
function<bool(const std::string*)> fcn = &std::string::empty;

//现在是正确的了,fcn是一个可调用对象,使用->*调用empty
std::find_if(svec.begin(), svec.end(), fcn);

② uso mem_fn generar un objeto invocable

  • A través de los conocimientos anteriormente, que desee utilizar la función, la forma debe ser proporcionada a los miembros de la llamada. También podemos tomar otro enfoque es utilizar las funciones de la librería estándar mem_fn para permitir que el compilador para inferir los miembros responsables del tipo de
  • mem_fn también se define en el archivo de cabecera funcional, y puede ser para generar un puntero de la exigible miembro
  • Y la función es diferente:
    • mem_fn puede llamar a los tipos de objetos, y un puntero de acuerdo con los miembros de la inferencia de tipos sin que el usuario especifica explícitamente
    • Por ejemplo: Nosotros usamos mem_fn generan un objeto invocable , el objeto toma un argumento de cadena y devuelve un valor booleano (compilador infiere automáticamente)
std::find_if(svec.begin(), svec.end(), mem_fn(&std::string::empty));
  • mem_fn objeto exigible generada por el llamado objeto, puede ser invocada por un puntero:
std::vector<std::string> svec;
	
auto f = mem_fn(&std::string::empty); //f接受一个string或者一个string*

f(*svec.begin()); //正确,传入一个string对象,f使用.*调用empty
f(&svec[0]);      //正确,传入一个string的指针,f使用.*调用empty
  • De hecho, podemos pensar mem_fn generan objetos que se puede llamar contienen un operador de llamada de función sobrecargada: acepta una cadena de *, otra cadena aceptable y

③ Usando bind genera una exigible

  • En exhaustividad, también podemos utilizar una función miembro objeto bind exigible generada a partir de:
std::vector<std::string> svec;

//选择范围中的每个string,并将其bind到empty的第一个隐式实参上
auto it = find_if(svec.begin(), svec.end(), bind(&string::empty, _1));
  • Función y lugares similares es cuando usamos el enlace, la función debe ser ejecutada para indicar un objeto se convierte en un parámetro implícito explícito . Mem_fn y lugares similares, se unen objeto invocable puede ser generada primer argumento es un puntero a la cadena, la cadena se puede citar:
std::vector<std::string> svec;

auto f = bind(&string::empty._1);
f(*svec.begin()); //正确,传入一个string对象,f使用.*调用empty
f(&svec[0]);      //正确,传入一个string的指针,f使用.*调用empty

 

发布了1504 篇原创文章 · 获赞 1063 · 访问量 43万+

Supongo que te gusta

Origin blog.csdn.net/qq_41453285/article/details/104710649
Recomendado
Clasificación