C++类基础(九)
创始人
2024-05-24 22:21:15
0

字面值类,成员指针与 bind 交互
● 字面值类:可以构造编译期常量的类型
– 其数据成员需要是字面值类型

#include
#include
class Str
{
public:Str(int val) //在运行期执行,导致#1处的错误: x(val){}
private:int x = 3;
};constexpr int a = 3; //OK,编译期字面值常量constexpr Str a(3); //#1Error: Constexpr variable cannot have non-literal type 'const Str'
int main()
{return 0;
}

– 提供 constexpr / consteval 构造函数 (小心使用 consteval )

#include
#include
class Str
{
public:constexpr Str(int val) //提供constexpr构造函数: x(val){}
private:int x = 3;
};constexpr Str a(3); //OKint main()
{return 0;
}
#include
#include
//clang++
class Str
{
public:consteval Str(int val) //OK since C++20,consteval修饰一个函数,每次调用该函数都会返回一个编译期常量。编译期/运行期调用该函数就会返回一个编译期/运行期常量,即既可以在编译期使用也可以在运行期使用: x(val){}
private:int x = 3;
};constexpr Str a(3);int main()
{return 0;
}
class Str
{
public:consteval Str(int val) //Error: Unknown type name 'consteval': x(val){}
private:int x = 3;
};constexpr Str a(3);int main()
{int x;Str a(x); //--std=c++2a x86-64 clang 10.0.1 OKStr b(x); //--std=c++2a x86-64 clang 11.0.0 Error: Call to consteval function 'Str::Str' is not a constant expressionStr c(x); //--std=c++2a x86-64 clang 12.0.1 Error: Call to consteval function 'Str::Str' is not a constant expressionStr d(x); //--std=c++2a x86-64 gcc9.4 Error: 'consteval' does not name a typeStr e(x); //--std=c++2a x86-64 gcc10.1 Error: the value of 'x' is not usable in a constant expressionreturn 0;
}

– 平凡的析构函数

class Str
{
public:constexpr Str(int val): x(val){}//~Str() = default; //平凡的析构函数,即编译器合成的析构函数(不写此行)~Str() {} //#1即使函数体为空也是用户定义的析构函数的逻辑,运行期销毁对象时调用
private:int x = 3;
};constexpr Str a(3); //编译器无法知道在编译期如何销毁该对象,使用#1处的析构导致编译失败int main()
{return 0;
}

– 提供 constexpr / consteval 成员函数 (小心使用 consteval )

class Str
{
public:constexpr Str(int val) //可在编译期调用,也可在运行期调用: x(val){}Str(double f) //只能在运行期调用: x(f){}constexpr int funexpr() const{return x+1;}consteval int funeval() const{return x+1;}
private:int x = 3;
};constexpr Str a(3);int main()
{Str b(3.0);b.funexpr(); //OKStr a(5.0);a.funeval(); //--std=c++2a x86-64 gcc 10.1 Errorreturn a.funexpr(); //OK
}

– 注意:从 C++14 起 constexpr / consteval 成员函数非 const 成员函数

class Str
{
public:constexpr Str(int val): x(val){}constexpr int fun() //C++11时constexpr函数缺省为const,即constexpr int fun() const,通常constexpr函数体只能包含一条返回语句return x+1;}
private:int x = 3;
};constexpr Str a(3);int main()
{return a.fun(); //OK, a是const变量
}
class Str
{
public:constexpr Str(int val): x(val){}constexpr int fun() const //C++14时constexpr函数缺省为非const,所以加入const修饰符{return x+1;}
private:int x = 3;
};int main()
{return a.fun(); //Error: 'this' argument to member function 'fun' has type 'const Str', but function is not marked const
}
constexpr int MyFun(int x) //C++14可以引入复杂的逻辑,函数体内的变量i是可以改变的,所以缺省是非const
{for(int i=0;i<10;++i){x += i;}return x;
}
class Str //字面值类
{
public:constexpr Str(int val): x(val){}constexpr int fun() const //C++14时constexpr函数缺省为非const,所以加入const修饰符{return x+1;}constexpr void inc(){x = x +1;}constexpr int read() const{return x;}
private:int x = 3;
};constexpr int MyFun()
{Str x(10);x.inc(); //可以通过constexpr void inc()修改字面值对象的中间状态x.inc();x.inc();return x.read();
}
int main()
{std::cout << MyFun() << std::endl;return 0;
}

在这里插入图片描述

● 成员指针
– 数据成员指针类型示例: int A::;
– 成员函数指针类型示例: int (A::
)(double);

#include
class Str
{
};
class Str2
{
};int main()
{int Str::*ptr; //ptr的类型是int Str::,ptr指向的基本类型是int,ptr位于类Str中void (Str::* ptr_fun)(); //ptr_fun的类型是void (Str::) ()。ptr_fun指向的基本类型是一个返回值为void的函数,ptr_fun位于类Str中int Str2::*ptr2;std::cout << std::is_same_v <

在这里插入图片描述

class Str
{
public:int x = 10;
};
class Str2
{
public:int y = 10;
};
int main()
{int Str::*ptr = &Str::x;int Str2::*ptr2 = &Str2::y;ptr2-ptr; //Error: Invalid operands to binary expression ('int Str2::*' and 'int Str::*')return 0;
}

– 成员指针对象赋值: auto ptr = &A::x;

class Str
{
public:int x = 10;
};
class Str2
{
public:int y = 10;
};
int main()
{int Str::*ptr = &Str::x; //using MemberVarPtr_13 = int Str::*; MemberVarPtr_13 ptr = &Str::x;int Str2::*ptr2 = &Str2::y; //  using MemberVarPtr_14 = int Str2::*; MemberVarPtr_14 ptr2 = &Str2::y;return 0;
}
class Str
{
public:int x = 10;int y = 10;void fun() {};void fun(double) {};
};
int main()
{int Str::*ptr = &Str::x;int Str::*ptr2 = &Str::y;void (Str::* ptr_fun) () = &Str::fun; //OKauto ptr_fun2= &Str::fun; //Error: Variable 'ptr_fun2' with type 'auto' has incompatible initializer of type ''return 0;
}
class Str
{
public:int x = 10;int y = 10;void fun() {};
};
int main()
{int Str::*ptr = &Str::x;int Str::*ptr2 = &Str::y;void (Str::* ptr_fun) () = &Str::fun; //OKauto ptr_fun2= &Str::fun; //OKreturn 0;
}

● 注意域操作符子表达式不能加小括号(否则 A::x 一定要有意义)

class Str
{
public:int x;int y;void fun() {};
};
int main()
{int Str::*ptr = &(Str::x); //Error: Invalid use of non-static data member 'x'return 0;
}
class Str
{
public:static int x; //静态变量int y;void fun() {};
};
int main()
{//ptr类型是int Str::*, &(Str::x)类型是int*,因为类Str中的x是静态整型,不依赖于类对象,单独占某块内存//int Str::*ptr = &(Str::x); //Error: Cannot initialize a variable of type 'int Str::*' with an rvalue of type 'int *'int val = Str::x; //OKint* ptr2 = &(Str::x); //Error: undefined reference to 'Str::x'return 0;
}
class Str
{
public:inline static int x; //内联静态int y;void fun() {};
};
int main()
{int* ptr2 = &(Str::x); //OKreturn 0;
}

– 成员指针的使用:
● 对象 .* 成员指针
● 对象指针 ->* 成员指针

class Str
{
public:int x;int y;void fun() {};
};
int main()
{int Str::*ptr = &Str::x;Str obj;obj.x = 3;std::cout << obj.*ptr << std::endl;Str* ObjPtr = &obj;std::cout << ObjPtr->*ptr << std::endl;return 0;
}

在这里插入图片描述

● bind 交互
– 使用 bind + 成员指针构造可调用对象

#include  //std::bind包含于该头文件中
class Str
{
public:int x;int y;void fun(double x){std::cout << x <auto ptr = &Str::fun;Str obj;(obj.*ptr)(100.0); //OK//(*ptr)(100.0); //Error: Indirection requires pointer operand ('void (Str::*)(double)' invalid)//auto x = std::bind(ptr, 100.0); //Error: In template: static_assert failed due to requirement 'integral_constant::value ? sizeof...(_BoundArgs) >= integral_constant::value + 1 : sizeof...(_BoundArgs) == integral_constant::value + 1' "Wrong number of arguments for pointer-to-member"auto y = std::bind(ptr, obj, 100); //OKy();return 0;
}

在这里插入图片描述

– 注意这种方法也可以基于数据成员指针构造可调用对象

class Str
{
public:int x;int y;void fun(double x){std::cout << x <Str obj;auto ptr2 = &Str::x;obj.*ptr2 = 3;auto x = std::bind(ptr2, obj); //OKstd::cout << x() << std::endl;return 0;
}

在这里插入图片描述

参考
深蓝学院:C++基础与深度解析
C++ Insights

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...