临时对象:
int &&ref = i++; r1 = 19; i =20; ref 和 i 之间没有什么关系 一些临时对象,是代码写的问题,统一称临时变量为临时对象 产生情况: 1) 以传值方式给函数传递参数(不推荐,建议传引用,不产生临时对象) 2) 类型转换生成的临时对象,隐式转换 3) 函数返回对象的时候(用变量来接,&,或者&& 接收,都会少调用一次析构,防临时变量被析构掉) 总结: Func();//函数引起消耗 Test temp; 会消耗一个构造和析构 return temp;会产生临时对象,占用一个拷贝构造函数,和析构函数
移动构造函数:
为了进一步提高程序效率 拷贝: Time::Time(const Time& temp){ ?}//const左值引用 移动: Time::Time(const Time&&temp){ ?}//右值引用&&
移动构造函数功能:
1)完成必要内存移动,斩断原对象和内存关系 2)确保移动后源对象处于一种销毁也没问题的状态 noexcept: 通知标准库移动构造函数不抛出任何异常,提高编译器效率 如果有自己的拷贝构造函数,自己的拷贝赋值运算符,或者自己的析构,那么编译器就不会为它合成移动构造函数和移动赋值运算符 如果没有移动,系统会默认用拷贝顶替 如果一个类没有定义任何自己版本的拷贝构造成员且类的每个非静态成员都可以移动 内置类型可移动 类类型的成员,这个类有对应的移动操作相关函数,就可以移动 此时编译器就能为我们合成一个移动函数
总结: 1 尽量给类添加移动构造函数和移动赋值运算符 2 noexcept 一定要加这个不抛出异常标识符 3 该给nullptr的给nullptr,让被移动对象处于一种能被析构状态 4 没有移动会调用拷贝
一个类只继承其直接基类的构造函数,默认,拷贝,移动构造不能继承 B :public A using A:A; 会根据A生成B的构造函数
虚基类,虚继承
派生列表中,同名基类只能出现一次 1 派生类可以通过两个直接基类分别继承同一个间接基类 2 直接继承某个基类,通过另一个基类间接继承该类 继承两次多余,占空间还可能产生冲突 虚基类是由最底层子类初始化,构造,析构
总结:小心翼神龙(虚继承),不太提倡使用 能用单一继承就不要用多重继承
类型转换构造函数
特点: 1 只有一个参数,而且该参数不是本类的const引用 (const &A) 2 在类型转换构造函数,要指定转换的方法 static_cast<int>(类名)
类对象转为函数指针 class R { ?? ?using tyfp = void(*)(int);//函数指针 public: ?? ?static void sss(int a)//静态成员函数 ?? ?{ ?? ??? ?cout << "" << endl; ?? ?} ?? ?operator tyfp() ?? ?{ ?? ??? ?return sss; ?? ?} } main: ?? ?R ref(123); ?? ?ref(111);//等同(ref.operator R::tyfp())(111); 尽量少用,代码可读性差
类成员函数指针
普通: 类名::*函数指针变量名 ? //声明一个普通成员函数指针 &类名:: 成员函数名 ? ? //获取类成员函数地址 ? “这是真正的内存地址” 类对象名.*函数指针变量名 //调用 指针名->*函数指针变量名 //调用
重点:成员函数是属于类的,不属于类对象,只要有类在就有成员函数地址在 但是如果要用这个指针,就必须要绑定到类对象上才能调用 class R { public: ?? ?R() {}; ?? ?void ptfun(int a) { cout << "ptfun" << endl; } }; int main() { ?? ?void (R::* myptr)(int); ?? ?myptr = &R::ptfun; ?? ?R ref,*pcc; ?? ?pcc = &ref; ?? ?(ref.*myptr)(100);//对象ref 调用指针变量myptr所指向的成员函数ptfun ?? ?(pcc->*myptr)(100);//对象pcc 调用指针变量myptr所指向的成员函数ptfun ?? ?return 0; }
虚函数 “这是真正的内存地址”
class R { public: ?? ?R() {}; ?? ? ?? ?virtual void vtfun(int a) { cout << "vtfun" << endl; }; private: ?? ?int temp; };
int main() { ?? ?R ref,*pcc; ?? ?pcc = &ref; ?? ?void (R:: * virFun)(int) = &R::vtfun; ?? ?(ref.*virFun)(100);//对象ref 调用指针变量virFun所指向的成员函数vtfun ?? ?(pcc->*virFun)(100);//对象pcc 调用指针变量virFun所指向的成员函数vtfun ?? ?return 0; }
静态成员函数指针 ?“这是真正的内存地址”
*函数指针变量名 使用 &类名::成员函数名获取成员函数地址
class R { public: ?? ?R() {}; ?? ?static void stfun(int a) { cout << "stfun" << endl; } private: ?? ?int temp; };
int main() { ?? ?R ref,*pcc; ?? ?pcc = &ref; ?? ?void(*stafun)(int) = &R::stfun; ?? ?stafun(100);//直接使用指针名即可调用 ?? ?stafun(200); ?? ?return 0; }
类成员变量指针:不是真正的内存地址”
普通成员变量
class R { public: ?? ?R() {}; ?? ?int m1 = 10; };
int main() { ?? ?int R::*dd = &R::m1;//并不是指向内存中的某个地址,而是该成员变量,与该类对象之间的偏移量 ?? ?R tempR; ?? ?tempR.*dd = 111;//通过类成员变量指针来修改成员变量值,等价于R.m1 = 111; ?? ?return 0; }
静态成员变量 “这是真正的内存地址”
class R { public: ?? ?R() {}; ?? ?static int m2; private: ?? ?int temp; }; int R::m2 = 100; int main() { ?? ?int* stp = &R::m2;//定义静态成员变量指针 ?? ?*stp = 20; ?? ?return 0; }
?
?
模板和泛型
模板是泛型编程基础 模板支持将类型作为参数的程序设计方式,从而实现了对泛型程序设计的直接支持
函数模板定义 template <typename T> T funAdd(T a, T b) { ?? ?T sum = a + b; ?? ?return sum; } 非类型模板参数 template<int a,int b> int funAdd2() { ?? ?int sum = a + b; ?? ?return sum; } int main() { ?? ?int cc = funAdd2<123, 11>(); ?? ?cout << cc << endl; ?? ?return 0; } 值必须要在编译时就能确定
template<typename T ,int a, int b> int funAdd3(T c) { ?? ?T sum = (int)c + a + b; ?? ?return sum; } int main() { ?? ?int cc = funAdd3<int,123, 11>(1); ?? ?cout << cc << endl; ?? ?return 0; }
|