07_类类型转换、继承、虚基类、 静态联编 与 动态联编、父子类指针、虚函数、类模板
来源:互联网 发布:网络策划是什么 编辑:程序博客网 时间:2024/06/05 19:47
- 目录
- 一类类型转换
- 二继承publicprivateprotected
- 三虚基类
- 四静态联编 与 动态联编
- 五父类指针与子类指针
- 六父类与子类指针释放
- 七虚函数虚基类多态
- 八异质链表
- 九类模板
- 十位运算算法
- 十一Rtti实时类型检测
- 十二高级new 对象
- 十三类包装器与函数包装器
- 十四类成员函数指针
【目录】
一、 类类型转换 3
1、 方法一:构造函数 3
2、 方法二:转换函数(注:只能是成员函数,不能是友元函数) 3
3、 转换函数 —> 类与类之间转换 3
二、 继承——public、private、protected 4
1、 多继承 :C++支持多继承,单继承; 5
2、 多态所能访问的是父类的函数; 5
3、 :public 类 ——公有继承可以访问除了私有以外的成员属性,且继承后保持父类的公有与保护属性不变; 5
4、 :private 类 ——私有继承可以访问除了私有以外的成员属性,但是继承后父类的公有和私有属性都变为子类的私有属性,所以不能继续继承下去。 5
5、 :protected 类 ——保护继承可以访问除了私有以外的成员属性,但是继承后父类的公有和私有属性都变为子类的保护属性,外部不能访问,所以可以无限继承下去。 5
6、 Static 公有成员变量 可以继承下去; 5
7、 Static 函数; 5
8、 基类初始化 : 5
9、 单继承函数重载: 6
10、 多继承简介: 6
三、 虚基类 7
1、 定义: 7
四、 静态联编 与 动态联编 9
1、 联编: 9
2、 静态联编 9
3、 动态联编 9
五、 父类指针与子类指针 9
1、 父类指针引用父类对象,完全正常引用; 9
2、 子类指针引用子类对象,覆盖父类的同名函数; 10
3、 父类指针引用子类对象,只能引用父类中的函数; 10
4、 子类指针,引用父类对象,子类不涉及内部数据的函数会调用成功(主要是没初始化)。 10
5、 注意: 10
六、 父类与子类指针释放 12
1、 父类引用子类–>内存泄漏 13
2、 子类引用父类–>内存越界 13
3、 解决:智能指针、虚析构函数 13
七、 虚函数(虚基类)——多态 13
1、 虚函数的作用: 13
2、 纯虚函数 15
3、 构造函数不能是虚函数 15
4、 虚析构函数—-解决内存泄漏 15
5、 抽象类不可以用于函数的参数以及返回值类型,抽象类指针是可以; 15
6、 抽象类叠加 16
八、 异质链表 16
1、 定义: 16
九、 类模板 16
1、 说明及构成: 16
2、 例子: 16
3、 两种数据类的的函数模板: 17
4、 C++的数组array也是类模板 17
5、 类模板做函数参数 20
6、 类模板做类模板参数 20
7、 C++11 final 与 override 21
8、 类模板的继承与多态 22
9、 类模板友元函数 24
10、 友元类类模板 25
11、 Static 与 类模板 26
12、 类嵌套以及类模板嵌套 27
十、 位运算算法 28
1、 加法: 28
2、 计位数: 29
十一、 Rtti(实时类型检测) 29
1、 成员变量覆盖: 29
十二、 高级new —对象 31
十三、 类包装器与函数包装器 32
十四、 类成员函数指针 33
1、 P与*p等价 33
2、 Cpp的函数指针 34
3、 Cpp的类成员函数指针 34
一、类类型转换
1、方法一:构造函数(转换构造函数,三种情况下发生)
2、方法二:转换函数(注:1、只能是成员函数,不能是友元函数;2、与操作符重载不同)
①.格式:
Operator T(){ /*伪码:执行自己的操作*/ Return T ;}/*--------------------------------------------------*/#include<iostream>using namespace std ;class mianji{ private : int x ; int y ; public : mianji( int x , int y ) { this->x = x ; this->y = y ; } operator int(){ /*转换函数*/ return this->x + this->y ; } friend ostream & operator <<( ostream & out , mianji & mm ) ;};ostream & operator <<( ostream & out , mianji & mm ) { out<<"output : "<< mm.x <<"+"<<mm.y<<"i"<<endl ; return out ;}int main( int argc , char** argv ) { mianji m1( 2 , 3 ) ;/*利用构造函数转换类型*/ cout<< m1 <<endl ; int x = m1 ; /*利用转换函数,将自己定义的类转化为基本类型*/ cout<< x <<endl ; system("pause") ; return 0 ;}
3、转换函数 —> 类与类之间转换
#include<iostream>using namespace std ;class mianji{ private : int x ; int y ; public : mianji( int x , int y ) { this->x = x ; this->y = y ; } operator int(){ return this->x + this->y ; } friend ostream & operator <<( ostream & out , mianji & mm ) ; friend class fushu ;};class fushu { private : int cx ; int cy ; public : fushu( int x , int y ):cx(x),cy(y){} operator mianji(){ mianji temp(0,0) ; temp.x = this->cx ; temp.y = this->cy ; return temp ; }} ;ostream & operator <<( ostream & out , mianji & mm ) { out<<"output : "<< mm.x <<"+"<<mm.y<<"i"<<endl ; return out ;}int main( int argc , char** argv ) { mianji m1( 2 , 3 ) ;/*利用构造函数转换类型*/ cout<< m1 <<endl ; int x = m1 ; /*利用转换函数,将自己定义的类转化为基本类型*/ cout<< x <<endl ; /*类与类之间的转换*/ fushu f1( 22 , 33 ) ; mianji mm(11,11) ; cout<< mm << endl ; /*以下是三种转化写法*/ mm = (mianji)f1 ; mm = f1 ; mm = mianji(f1) ; cout<< mm <<endl ; system("pause") ; return 0 ;}
二、继承——public、private、protected
1、多继承 :C++支持多继承,单继承;
2、多态所能访问的是父类的函数;
fu *p = new son ;p->show() ; /*这里调用的是父类的show函数*/p->boy() ;/*这是子类特有的公有函数,多态父类指针不能访问*//*-------------------------------------------------------*/ fu *p = new son ; p->show() ; son *ps = reinterpret_cast<son *>(p) ; ps->show() ;/*这里调用的是子类的show函数*/ ps->fu::show() ;/*这里调用的是父类的show函数*/ ps->boy() ;
3、:public 类 ——公有继承可以访问除了私有以外的成员属性,且继承后保持父类的公有与保护属性不变;
4、:private 类 ——私有继承可以访问除了私有以外的成员属性,但是继承后父类的公有和私有属性都变为子类的私有属性,所以不能继续继承下去。
5、:protected 类 ——保护继承可以访问除了私有以外的成员属性,但是继承后父类的公有和私有属性都变为子类的保护属性,外部不能访问,所以可以无限继承下去。
6、Static 公有成员变量 可以继承下去;
7、Static 函数;
8、基类初始化 :
#include<iostream>using namespace std ;class fu { public : fu(){ cout<<"b fu"<<endl ; } fu( int x ) : x(x) { cout<<"b fu num "<< this->x <<endl ; } ~fu(){ cout<<"e fu"<<endl ; } int x ;};class son : public fu { public : son(){ cout<<"b son"<<endl ; }/* 1、这里初始化必须用父类的带参数的构造函数,不然会直接调用父类的无惨构造函数; 2、可以去掉下面:fu(x) ,然后执行看下结果*/ son( int x ):fu(x) { cout<<"b son num "<<this->x<<endl ; } ~son(){ cout<<"e son"<<endl ; }};int main( int argc , char** argv ) { son s(3) ; system("pause") ; return 0 ;}
9、单继承函数重载:
①.子类的同名函数会覆盖父类的函数,即使参数类型不一样;(即使父类有很多同名的重载函数,只要子类有一个同名函数,就会全部覆盖父类的同名函数)
10、多继承简介:
①.多继承子类的构造函数会根据继承的先后顺序调用
#include<iostream>using namespace std ;class fu { public : fu(){ cout<<"b fu"<<endl ; } fu( int x ) : x(x) { cout<<"b fu num "<< this->x <<endl ; } ~fu(){ cout<<"e fu"<<endl ; } void show( void ){ cout<<"fu"<<endl ; } int x ;};class son { public : son(){ cout<<"b son"<<endl ; } son( int x ): y(x) { cout<<"b son num "<<this->y<<endl ; } ~son(){ cout<<"e son"<<endl ; } int y ; void show( void ){ cout<<"show"<<endl ; }};class chen : public fu , public son { public : chen(){ cout<<"b chen"<<endl ; } chen( int x ) : son(x) , fu(x) { cout<<"b chen num "<<this->x<<endl ; } ~chen(){ cout<<"e chen"<<endl ; } /*void show( void ){ cout<<"chen"<<endl ; }*/};int main( int argc , char** argv ) { fu *c = new chen(2) ; c->show() ; delete c ; system("pause") ; return 0 ;}
②.多继承所继承的类中如果有同名函数,必须指明调用是所继承的类中哪个类的函数:
chen *c = new chen(2) ; c->fu::show() ;
三、虚基类
1、定义:
①.对C++虚基类的描述曰“共享继承”,名曰“各派生类的对象共享基类的的一个拷贝”,其实说白了就是解决多重多级继承造成的二义性问题。例如有基类B,从B派生出C和D,然后类F又同时继承了C和D,现在类F的一个对象里面包含了两个基类B的对象,如果F访问自己的从基类B那里继承过来的的数据成员或者函数成员那么编译器就不知道你指的到底是从C那里继承过来的B对象呢还是从D那里继承过来的B对象。
②.于是虚基类诞生了,将C和D的继承方式改为虚继承,那么F访问自己从B那里继承过来的成员就不会有二义性问题了,也就是将F对象里的B对象统一为一个,只有一个基类B对象,下面是一段代码说明了对虚基类的使用。(注【己】:感觉要自己理解)
#include<iostream>using namespace std ;class A {public : A(){ cout<< " A creat " << endl ; }; A( int a ) : x(a) { cout<< " A creat num -->" << this->x << endl ; }; ~A(){ cout<< " A delete " << endl ; } int x ; int y ;};class B : virtual public A{ public : B(){ cout<< " B creat " << endl ; }; B( int a ) : A(a){ cout<< " B creat num --> " << this->x << endl ; }; ~B(){ cout<< " B delete " << endl ; }};class C : virtual public A { public : C(){ cout<< " C creat " << endl ; }; C( int a ) : A(a){ cout<< " C creat num --> " << this->x << endl ; }; ~C(){ cout<< " C delete " << endl ; }};class BC : public B , public C { public : BC(){ cout<< " BC creat " << endl ; }; BC( int a , int b ) : B(a) , C(b) BC( int a , int b ) : A( a+b ) BC( int a , int b ) : A( a+b ) , B(a) , C(b){ cout<< " BC creat A num --> " << this->A::x ; cout<< " BC creat B num --> " << this->B::x ; cout<< " BC creat C num --> " << this->C::x << endl ; }; ~BC(){ cout<< " BC delete " << endl ; }};int main( int argc , char** argv ) { BC aaa(2,3) ; /*去了virtual后看输出结果*/ aaa.y = 4 ; /*如果不采用virtual,则编译不能通过*/ system("pause") ; return 0 ;}
四、静态联编 与 动态联编
1、联编:
①.定义 :联编就是将模块或者函数合并在一起生成可执行代码的处理过程,同时对每个模块或者函数调用分配内存地址,并且对外部访问也分配正确的内存地址,它是计算机程序彼此关联的过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。
2、静态联编
①.定义:是指在编译阶段就将函数实现和函数调用关联起来,因此静态联编也叫早绑定,在编译阶段就必须了解所有的函数或模块执行所需要检测的信息,它对函数的选择是基于指向对象的指针(或者引用)的类型,C语言中,所有的联编都是静态联编,据我所知道的,任何一种编译器都支持静态联编(废话)。函数重载也是一种。
3、动态联编
①.定义:是指在程序执行的时候才将函数实现和函数调用关联,因此也叫运行时绑定或者晚绑定,动态联编对函数的选择不是基于指针或者引用,而是基于对象类型,不同的对象类型将做出不同的编译结果。C++中一般情况下联编也是静态联编,但是一旦涉及到多态和虚拟函数就必须要使用动态联编了。If ,switch语句就是。
五、父类指针与子类指针
1、父类指针引用父类对象,完全正常引用;
2、子类指针引用子类对象,覆盖父类的同名函数;
3、父类指针引用子类对象,只能引用父类中的函数;
4、子类指针,引用父类对象,子类不涉及内部数据的函数会调用成功(主要是没初始化)。(使用dynamic_cast
#include <iostream>using namespace std ;class fu { private : int age ; public : fu(){ age = 10 ; cout<<"fu"<<endl ; } ~fu(){} void fufu(){ cout<<"fufu"<<this->age<<endl ; } void printc(){ cout<<"fu--print"<<endl ; }} ;class zi : public fu { private : char *strzi ; public : zi(){ strzi = "son" ; cout<<"zi"<<endl ; } ~zi(){} void zizi(){ cout<<"zizi" << this->strzi <<endl ; } void printc(){ cout<<"zizi" << this->strzi <<endl ; cout<<"zi--print"<<endl ; }} ;void main(){ { //fu *pfu = new fu; //delete pfu; } { /// zi *pzi = new zi; // delete pzi;} { //fu *pfu = new zi; //delete pfu;//内存泄漏 } { //fu *pfu = new fu; zi *pzi = static_cast<zi *>(new fu); delete pzi;//内存越界,超过界限释放内存,有时出错,有时无措 } std::cin.get();}void main3(){ zi *pzi(nullptr); pzi->zizi(); std::cin.get();}void main4(){ fu *pfu = new fu; zi *pzi = static_cast<zi *>(pfu); pzi->fufu(); pzi->zizi(); pzi->fu::print(); //pzi->print(); //std::cout << pzi->strzi << std::endl; //pzi->print(); std::cin.get();}void main2(){ fu *pfu = new zi; pfu->print(); pfu->fufu(); std::cin.get();}void main1(){ fu *pfu = new fu; pfu->print(); pfu->fufu(); zi *pzi = new zi; pzi->print();//子类覆盖父类 pzi->zizi(); pzi->fufu(); /* fu fu1; fu1.print(); fu1.fufu(); */ std::cin.get();}
六、父类与子类指针释放
1、父类指针引用子类对象–>内存泄漏
2、子类指针引用父类对象–>内存越界
{ //fu *pfu = new zi; //delete pfu;//内存泄漏 } { //fu *pfu = new fu; zi *pzi = static_cast<zi *>(new fu); delete pzi;//内存越界,超过界限释放内存,有时出错,有时无措 }
3、解决:智能指针、虚析构函数(内存泄露)
七、虚函数(虚基类)——多态
1、虚函数的作用:
①.是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。——-(己:这才是继承所要实现的真正目的,没有虚函数的基类指针(不经过类型转换)访问基类的同名函数,不能访问派生类中的同名函数,这个才和Java学习的继承一样)。
#include<iostream>//没有virtual,会一直调用基类的方法//virtual的//虚函数现代编译器会直接分配一个指针存储虚函数表的位置,class fu{public: /*这里的virtual可以去掉后看输出结果*/ virtual void name() { std::cout << "父类"; std::cout << "x=" << x << "\n"; } int x; fu(int a) :x(a) { }} ;class zi :public fu{public: void name() { std::cout << "子类"; std::cout << "x=" << x << ",y="<<y<<"\n"; } int y; zi(int a, int b) :fu(a), y(b) { }};class sun :public zi{public: void name() { std::cout << "孙类"; std::cout << "x=" << x << ",y=" << y <<",z="<<z<< "\n"; } int z; sun(int a, int b, int c) :zi(a, b), z(c) { }void main(){ std::cout << sizeof(fu) << std::endl; fu fu1(1); zi zi1(2,3); sun sun1(4,5,6); fu *pfu; pfu = &fu1; pfu->name();//1 pfu = &zi1; pfu->name();//2 pfu = &sun1; pfu->name();//4 //((zi*)pfu)->name(); //((sun*)pfu)->name(); std::cin.get();}void main1(){ /* fu *pfu = new fu; pfu->name(); zi *pzi = new zi; pzi->name(); sun *psun = new sun; psun->name(); zi *pzifu = static_cast<zi *>(pfu); pzifu->name(); sun *psunfu = static_cast<sun *>(pfu); psunfu->name(); std::cin.get(); */}
②.重载基类中的虚函数必须函数名,参数,返回值都一样,即绝对匹配。
2、纯虚函数
①.在基类中没有定义,必须在子类中实现,跟Java中的接口一样;
②.带了纯虚函数的类是抽象类,不能实例化;
③.纯虚函数的说明:
第一种:
Virtual void show () = 0{ cout << “good” << endl ;}
第二种:
Virtual void show () = 0 ;
其实,实不实现都是没问题的,派生类都必须重写。
3、构造函数不能是虚函数
①.原因:不会再构造,没有办法创建子类中的父类对象
4、虚析构函数—-解决内存泄漏
①.虚析构函数,让父类指针正确的释放子类对象的内存;
②.解决上面内存泄漏的情况,在基类指针引用派生类对象释放内存时,会自动调用基类的析构函数。虚析构函数就是这个作用。
5、抽象类不可以用于函数的参数以及返回值类型,抽象类指针是可以;
class base{public: //纯虚函数,有无定义都可以 //有一个纯虚函数,都是抽象类,无法实例化 virtual void run()=0 //限定一个类不能实例化,专门的接口 { std::cout << "base run\n"; } virtual ~base() { }};//抽象类不可以用于函数的参数以及返回值类型//抽象类指针是可以base * test( base *p){ base *pbase(nullptr); return pbase;}
6、抽象类叠加
①.抽象类中还有抽象类,软件迭代式开发拓展接口;
八、异质链表
1、定义:
①.程序中,用基类类型指针可以生成一个连接不同派生类对象的动态链表,即每个节点指针可以指向类层次中不同的派生类对象。这个节点类型不同的链表称为异质链表。
九、类模板
1、说明及构成:
2、例子:
#include<iostream>using namespace std ;template<class T>class comx{ public : T a,b ; T add(){ return a+b ; }};int main(){ comx<int> com1 ; com1.a = 5 ; com1.b = 6 ; cout<< com1.add() << endl ; cin.get() ; return 0 ;}
3、两种数据类的函数模板:
#include<iostream>using namespace std ;#include<string>/*定义两种数据类的的函数模板*/template<class T1 , class T2>class my{ public : T1 t1 ; T2 t2 ; my( T1 a , T2 b ):t1(a),t2(b){ } void show(){ cout<<t1<<"::"<<t2<<endl ; } };int main( int argc , char **argv ){ my<int , string> m( 1 ,"55dd" ) ; m.show() ; system("pause") ; return 0 ;}
4、C++的数组array也是类模板
/*main.cpp*/#include <iostream>#include <string>#include "Array.h"#include"Array.cpp"/*必须两个都包含,在没明确类型之前,编译器也不知道用哪个函数*/using namespace std;void main11(){ /* string str = "calc"; Array<string> myarray(5);//构造五个元素数组 for (int i = 0; i < myarray.size();i++) { str += "X"; myarray.set(str, i); std::cout << myarray.get(i) << std::endl; } */ std::cin.get();}void main22(){ Array<int,5 > myarray; for (int i = 0; i < myarray.size(); i++) { myarray.set(i, i); std::cout << myarray[i] << std::endl; } std::cin.get();}template<class T, int n>//类模板作为参数,类型无比明确void print(Array<T,n> &myarray){ for (int i = 0; i < myarray.size();i++) { std::cout << myarray[i] << std::endl; }}void main(){ Array<int, 5 > myarray; for (int i = 0; i < myarray.size(); i++) { myarray.set(i, i); } print(myarray); std::cin.get();}/***Array.h***/#pragma oncetemplate<class T,int n>class Array{public: Array(); Array(int length); ~Array(); int size(); T get(int num); T& operator [](int num);//重载【】 void set(T data, int num);public: T *pt; //int n;//长度};/****Array.cpp***/#include "Array.h"template<class T, int n>//int n不可以修改,不是类的内部成员Array<T,n>::Array(){ //this->pt = nullptr;//空指针 //this->n = 0; this->pt = new T[n];}template<class T, int n>//每一个函数都必须模板Array<T,n>::Array(int length){ this->pt = new T[length]; //n = length;}template<class T, int n>//每一个函数都必须模板Array<T,n>::~Array(){ //n = 0; delete[] this->pt;}template<class T, int n>//每一个函数都必须模板int Array<T,n>::size(){ return n;}template<class T, int n>//每一个函数都必须模板T Array<T,n>::get(int num)//num是数组的下标{ if (num >= n ||num <0)//报错 { //异常 } else { return *(this->pt + num); }}template<class T, int n>//每一个函数都必须模板void Array<T,n>::set(T data, int num){ if (num<0 || num>=n) { } else { *(pt + num) = data; }}template<class T, int n>//每一个函数都必须模板T& Array<T,n>::operator [](int num){ if (num < 0 || num>=n) { } else { return *(pt + num); }}
5、类模板做函数参数
①.当一个函数拥有类模板参数时,这个函数必定为函数模板;
template<class T, int n>//类模板作为参数,类型特别明确void print(Array<T,n> &myarray){ for (int i = 0; i < myarray.size();i++) { std::cout << myarray[i] << std::endl; }}
6、类模板做类模板参数
#include<iostream>#include<string>using namespace std;//类模板当作一个类的参数//设计STL时候用到//面试,类模板当作参数template<class T>class ren //一个通用的类的类模板{public: T name; ren(T t) :name(t) { }};template< template<class T> class T1 > //使用类模板当作模板参数的类class people{public: T1<string> t1x="123123";//T1必须实例化 。必须结合 T1<string> num = "ABC"; //等价于ren类型 //T1 x; people(T1<string> t1) { std::cout << typeid(t1).name() << std::endl; std::cout << typeid(T1).name() << std::endl; std::cout << t1.name << std::endl; /*t1x = t1; num = t1;*/ }};void main(){ ren<string> ren1("hello8848"); //基本数据类型 people<ren> people1(ren1);//嵌套的类模板 //std::cout << people1.t1x.name << std::endl; //std::cout << people1.num.name << std::endl; //std::cout << people1.str << std::endl; std::cout << people1.t1x.name << std::endl; std::cout << people1.num.name << std::endl; std::cout << ren1.name << std::endl; std::cin.get();}
7、C++11 final 与 override
#include<iostream>//C++11 final override针对虚函数//final拒绝重载,某些情况下,接口拒绝被重写//加了final关键字的虚函数,无法被重写,预留接口//override,警示符,声明我重写父类的方法,父类没有接口,会提示出错class ye{public: //final”函数必须是虚函数 virtual void print() final //虚函数无法重写 { std::cout << "爷爷\n"; } virtual void run() { std::cout << "爷爷run\n"; }};class ba:public ye{public: //警示作用,强调我覆盖了父类的方法,必须是虚函数 void runa () override { std::cout << "爸爸run\n"; }};void main1(){ ba ba1; ba1.run(); std::cin.get();}
8、类模板的继承与多态
①.模板类:是类模板的实例;类模板:是模板,不能直接生成类对象。
②.类模板可以从模板类派生 ;
③.类模板可以从非类模板派生 ;
④.模板类可以从类模板派生 ;
⑤.非模板类可以从类模板派生 ;
#include <iostream>#include <string>//模板类之间继承//类模板可以直接继承类模板,类型必须传递//普通类继承类模板,需要明确类型实例化类模板//类模板继承普通类,常规的操作方式//类模板当作普通哦类,需要模板参数对类进行实例化template<class T> //抽象模板类class myclass{public: T x; myclass(T t) :x(t) { } virtual void print() = 0;};template<class T>class newclass :public myclass<T> //继承必须明确类型{public: T y; newclass(T t1, T t2) :myclass(t1), y(t2) { } void print() { std::cout << x <<" " <<y<< std::endl; }};void main(){ myclass<int > *p=new newclass<int>(10,9); p->print(); std::cin.get();}void mainyz(){ myclass<int> *p = new newclass<int>(10,9); p->print(); std::cin.get();}void main1(){ //newclass<double> my1(10.9, 2.3); //my1.print(); newclass<std::string> my1("abc", "xyz"); my1.print(); std::cin.get();}/*-----------------------------------------------------------------------------------------------------------------*/class xyz{public: int x; int y; int z; xyz(int a, int b, int c) :x(a), y(b), z(c) { } void print() { std::cout << x << y << z; }};template<class T>class newxyz :public xyz{public: T a; newxyz(T t1,int a1,int b1,int c1) :xyz(a1,b1,c1),a(t1) { } void print() { std::cout << "Ta=" << a << std::endl; std::cout << x << y << z << std::endl; }};class classrun:public newxyz<int >//普通类继承模板类需要实例化{public: int d = 1000; classrun(int a2, int b2, int c2, int d2) :newxyz<int>(a2,b2,c2,d2) { } void print() { std::cout << d << x << y << z << a; }};void mainy(){ classrun run1(1, 2, 3, 4); run1.print(); std::cin.get();}void mainx(){ std::string str1 = "china"; newxyz<std::string> new1(str1,10,90,89); new1.print(); std::cin.get();}
9、类模板友元函数
①.类模板重载:
②.类模板友元函数
条件1:友元函数如果在外部,第一声明要加类型T如:printA
条件2:必须要声明类还有函数
#include <iostream>#include <string>#include <vector>template<class T> class myclass;template<class T> void print(myclass<T> & my, T t1);template<class T> class myclass{public: //friend void print(myclass<T> & my, T t1); //友元函数放在模板类的内部,实现重载 friend void print<T>(myclass<T> & my, T t1);/*就是这个红色的T忘记加了,搞了半天*/ friend myclass * operator+(const myclass<T> & my1, const myclass<T> &my2) { //myclass class1 栈,用完了马上释放 //堆上申请一个 myclass<T> * p = new myclass<T>(my1.x + my2.x, my1.y + my2.y); return p; } myclass(T t1, T t2) :x(t1), y(t2) { } //访问私有需要友元, private: T x; T y;};template<class T>void print(myclass<T> & my, T t1){ std::cout << typeid(t1).name() << std::endl; std::cout << my.x << " " << my.y << std::endl;}void main(){ myclass<int> my1(19, 29); myclass<int> my2(11, 1); print(my1, 10); //printA(my1); myclass<int> *pclass = my1 + my2; print(*pclass,10); std::cin.get();}
10、友元类类模板
#include<iostream>template <class T> class myclass;template<class T> class runclass;//友元类必须声明类的存在,//需要声明友元类,必须要与类型相关template <class T>class myclass{public: myclass(T t) :x(t) { } friend class runclass<T>;//声明友元类private: T x; //模板友元类 //int y;访问与T无关的类型,普通友元类};template<class T>class runclass{public: void print(const myclass<T> & my) { std::cout << my.x << std::endl; }};void main(){ myclass<double> my1(19.8); runclass<double> run1; run1.print(my1); std::cin.get();}
11、Static 与 类模板
#include <iostream>#include<string>//类模板的static成员,对象,类名《类型》//不同类型的静态成员变量,地址不一样//相同类型的静态成员变量,地址一样template<class T>class myclass{ static int data;public: static int num;//声明 T a; myclass(T t) :a(t) { num++; data++; } static void run() { //this->a; std::cout << data << std::endl; std::cout << typeid(T).name() << "\n"; }};template<class T>int myclass<T>::num = 0;template<class T>int myclass<T>::data = 0;//静态变量,静态函数,同类,共享的//类型不同,不是共享void main(){ myclass<int > my1(10); myclass<double > my2(10.9); myclass<int > my4(10); myclass<int>::run(); myclass<int>::run(); myclass<int>::run(); my1.run(); myclass<double>::run(); //myclass<int>::data; std::cin.get();}void mainA(){ myclass<int > my1(10); myclass<double > my2(10.9); myclass<std::string > my3("1234"); myclass<int > my4(10); std::cout << &my1.num << std::endl; std::cout << &my2.num << std::endl; std::cout << &my3.num << std::endl; std::cout <<&my4.num << std::endl; std::cout << &myclass<int >::num << std::endl; std::cout << &myclass<float >::num << std::endl; std::cin.get();}
12、类嵌套以及类模板嵌套
①.类嵌套
#include <iostream>class myclass{public: class newclass { public: int num; }new1;//类的嵌套};class newnewclass :public myclass{};void main(){ newnewclass newx; newx.myclass::new1.num=10; std::cout << newx.new1.num; std::cin.get();}void main1(){ myclass myclass1; myclass1.new1.num = 19; std::cout << myclass1.new1.num; std::cin.get();}
②.模板类嵌套
#include<iostream>template<class T>class myclass{public: class newclass { public: int num; }new1;//定义的方式 newclass new2; template<class V> class runclass { public: V v1; };//类模板后面不可以直接初始化 runclass<T> t1; runclass<double> t2;};void main(){ myclass<int > my1; my1.new1.num = 10; my1.t1.v1 = 12; my1.t2.v1 = 12.9; std::cout << my1.t1.v1 << "\n" << my1.t2.v1; std::cin.get();}
十、位运算算法
1、加法:
void add( int a , int b ){ if( 0==b ){ cout << a << ":::" << b << endl ; }else{ int res = a^b ; int wei = (a&b)<<1 ; cout<<"1"<<endl ; add( res , wei ) ; }}
2、计位数(计算1的位数):
①.第一种:
while (num) { i++; num &= num - 1;//让数据趋向于0 } std::cout << i << std::endl;
②.第二种:
int get1(int num){ int count = 0;//表示位数 unsigned int flag = 1; while (flag) { if (num & flag) //不为0就自增 { count++; } flag = flag << 1; } return count ;}
十一、Rtti(实时类型检测)
1、成员变量覆盖:
#include <iostream>//rtti,实时类类型检测,//typeid().name()//dynamic_cast必须依赖于虚函数表//类型不匹配转换失败,返回为空。类型安全//成员变量的覆盖//虚函数有虚函数表确定数据类型class A{public: int num; static int data; virtual void run() { std::cout << "Arun\n" ; }};int A::data=1 ;class B:public A{ public: int num=0; static int data; void run() { std::cout << "Brun\n"; } void test() { std::cout << num<<"\n"; std::cout << "Btest\n"; }};int B::data = 2;void main4(){ A a1; B b1; A *p1 = &a1; A *p2 = &b1; B *p3(nullptr); //p3 = static_cast<B *>(p1);//直接赋地址,不安全,与虚函数无关 p3 = reinterpret_cast<B*>(p2); std::cout << p3 << "\n"; p3->test(); std::cin.get();}void main3(){ A a1; B b1; A *p1 = &a1; A *p2 = &b1; B *p3(nullptr); //p3 = dynamic_cast<B*>(p2); //dynamic必须要有虚函数,根据虚函数表转换,不能转换 //转换失败为空 //类的空指针可以调用不调用数据的函数 //转换成功就是地址 std::cout << p3 << "\n"; p3->test(); std::cin.get();}void main2(){ //A *p1 = new A; //A *p2 = new B; A a1; B b1; A *p1 = &a1; A *p2 = &b1; std::cout << typeid(p1).name() <<" "<< typeid(p2).name() << std::endl; std::cout <<( typeid(p1) == typeid(p2))<<"\n"; std::cout << typeid(*p1).name() << " " << typeid(*p2).name() << std::endl; std::cout << (typeid(*p1) == typeid(*p2)) << "\n";//重载的方式判定类型是否一致 std::cin.get();}void main1(){ B b1; b1.num = 10;//覆盖现象 b1.A::num = 20; std::cout << b1.num << "\n" << b1.A::num << std::endl; std::cout << b1.data <<" "<< b1.A::data << "\n"; std::cout << &b1.data << " " << &b1.A::data << "\n"; std::cin.get();}
十二、高级new —对象
#include <iostream>class myclass{public: myclass() { std::cout << "创建\n"; } ~myclass() { std::cout << "销毁\n"; }};void main(){ char *pcathe = new char[1024]; char *pcatheend = pcathe + 1024; std::cout <<(void*) pcathe << " " << (void*)pcatheend << std::endl; myclass *p = new(pcathe)myclass[10];//限定区域分配内存,覆盖模式 std::cout << p << std::endl; //delete[] p;一般不需要delete.自动覆盖 std::cout << p << std::endl; p = new(pcathe)myclass[10]; std::cout << p << std::endl; //delete[] p;//只能释放一次 std::cout << p << std::endl; /*常规方式 myclass *pclass = new myclass[10]; std::cout << pclass << std::endl; delete []pclass; pclass = NULL; std::cout << pclass << std::endl; pclass = new myclass[10]; std::cout << pclass << std::endl; delete [] pclass; std::cout << pclass << std::endl; */ std::cin.get();
十三、类包装器与函数包装器
#include<iostream>template<typename T,typename F>T run(T t, F f) //包装器,实现一个操作接口,操作多个类的方法{ return f(t);}int add(int num){ return num + 10;}class myclass{public: int num; myclass(int data) :num(data) { } int operator ()(int X) { return X*num; }};class myclassA{public: int num; myclassA(int data) :num(data) { } int operator ()(int X) { std::cout << "A\n"; return X-num; }};void main(){ myclass my1(5); std::cout << run(101,my1) << std::endl; std::cout << run(101, myclassA(51)) << std::endl; std::cin.get();}void main1(){ auto num = 100; auto func = add; std::cout << run(num, add) << std::endl; std::cin.get();}
十四、类成员函数指针
1、P与*p等价
#include<stdio.h>int addC(int a, int b){ return a + b;}void run(){ printf("\nrun");}void main1(){ int(*p)(int, int) = addC; void(*p1)() = run; printf("%d\n", p(1, 2)); printf("%d\n", (*p)(1, 2)); //*p编译器自动将*p解释为p printf("%d\n", (**********p)(1, 2)); //*p编译器自动将*p解释为p printf("%d\n", (&(**p))(1, 2)); //&没有*不可以执行,超过两个地址就不可以 //&p不能, //printf("%d\n", (&(p))(1, 2)); printf("%p,%p,%p", &p, *p, p); printf("\n%p,%p,%p", &p1, *p1, p1); //printf("%d\n", (&p)(1, 2)); //取地址,取就是CPU即将调用函数执行,C语言内嵌ASM //老版本,*p,p,&p getchar();}
2、Cpp的函数指针
#include <stdio.h>#include<iostream>void add(int a, int b){ std::cout << a + b << std::endl;}void mainA(){ void(*p)(int, int) = add; p(1, 2); (*p)(1, 2);//函数指针,会被当作指针来处理,*p与p效果一样 (**************p)(1, 2);//函数指针,会被当作指针来处理,*p与p效果一样 (*&p)(1, 2); (*******&p)(1, 2); std::cout << (void *)p << " " << (void *)(*p) << std::endl; std::cout << typeid(p).name() << std::endl; std::cout << typeid(*p).name() << std::endl; std::cout << typeid(&p).name() << std::endl; std::cout << typeid(*&p).name() << std::endl; //C++编译器会自动将*p处理为p // std::cin.get();}
3、Cpp的类成员函数指针
#include<iostream>#include<stdio.h>//类成员函数指针,类成员函数指针数组,类成员二级函数指针class com{private: int a; int b;public: com(int x, int y) :a(x), b(y) { } int jia(int a, int b) { return a + b; } int jian(int a, int b) { return a - b; } int cheng(int a, int b) { return a * b; } int chu(int a, int b) { return a / b; }};void main1x(){ com com1(100, 20); auto fun1 = &com::jia; int(com::*p)(int, int) = &com::jia; std::cout << (com1.*p)(10, 20) << std::endl;//引用对象,类成员函数指针 std::cout << typeid(p).name() << std::endl; std::cout << typeid(fun1).name() << std::endl; std::cin.get();}typedef int(com::*P)(int, int);void main(){ com com1(100, 20); //P fun1[4] = { &com::jia, &com::jian, &com::cheng, &com::chu }; //类成员函数指针数组 int(com::*fun1[4])(int, int) = { &com::jia, &com::jian, &com::cheng, &com::chu }; for (int i = 0; i < 4; i++) { std::cout << (com1.*fun1[i])(10, 20) << std::endl; } int(com::**funp)(int, int) = fun1;//指向类成员函数指针的指针 for (; funp < fun1 + 4; funp++) { std::cout << (com1.**funp)(10, 20) << std::endl; printf("%p", *funp); } for (int i = 0; i < 4; i++) { auto func = fun1[i]; std::cout << typeid(func).name() << std::endl; printf("%p", func); } std::cin.get();}
- 07_类类型转换、继承、虚基类、 静态联编 与 动态联编、父子类指针、虚函数、类模板
- 静态联编,动态联编,类指针之间的关系,虚函数与多态性,纯虚函数,虚析构函数
- 面向对象技术,多态,重载,静态联编与动态连编,虚函数,抽象类,虚析构函数
- 面向对象技术,多态,重载,静态联编与动态连编,虚函数,抽象类,虚析构函数
- C++ 虚函数、静态联编和动态联编、抽象类
- 静态联编与动态联编
- 动态联编与静态联编
- 静态联编与动态联编
- C++ 虚函数、静态联编、动态联编
- 虚函数,静态联编与动态联编(读书笔记)
- C++中的虚函数与静态联编和动态联编
- 虚函数及静态联编与动态联编---学习笔记
- C++的静态绑定(称静态联编或者早绑定)和动态绑定(动态联编或者晚捆绑) 类继承virtural中用的
- C++虚函数与动态联编
- 动态联编与虚函数
- C++虚函数与动态联编
- C++多态篇1一静态联编,动态联编、虚函数与虚函数表vtable
- C++多态篇1一静态联编,动态联编、虚函数与虚函数表vtable
- CSV文件
- Zookeeper(一)分布式事务
- Myeclipse Loading org.eclipse.mlyn.tasks.ui卡死
- maven报错 pom.xml
- 蓝桥 十六进制转十进制
- 07_类类型转换、继承、虚基类、 静态联编 与 动态联编、父子类指针、虚函数、类模板
- redis&memcached for windows 安装与使用
- 初识.net界面程序(12)——按钮外观设计练习
- windows
- Tomcat
- 数据结构与算法之排序
- Spark性能调优(二)
- 64bit centos如何编译 32bit的程序
- 1、不一样的C++系列--C到C++的升级