C++学习
http://blog.chinaunix.net/uid-20465760-id-1944082.html
构造函数:
构造函数的作用:初始化对象的数据成员。
复制构造函数解释举例:
class Complex { private : double m_real; double m_imag; public: // 复制构造函数(也称为拷贝构造函数) // 复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中 // 若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询有关 “浅拷贝” 、“深拷贝”的文章论述 Complex(const Complex & c) { // 将对象c中的数据成员值复制过来 m_real = c.m_real; m_img = c.m_img; } };
C++中多重继承构造函数调用的先后顺序:
多重继承与单继承类似,也是先执行基类构造函数,按照派生类的声明从左到右依次执行
http://www.cnblogs.com/hu983/p/5524682.html
http://blog.csdn.net/u012954083/article/details/23253749
#include <cstdio> #include <iostream> using namespace std;
class A{ public: A(){ cout<<"A"<<endl; } }; class B{ public: B(){ cout<<"B"<<endl; } }; class C:public B,public A{ public: A a; C(){ cout<<"C"<<endl; } }; int main(){ C c; return 0; }
输出: B A A C 先按照派生类声明时从左到右先执行类B的构造函数,再执行类A的构造函数,所以输出B、A,之后由于类C中A a;这个语句实例化类A,所以执行类A的构造函数输出A,最后执行类C的构造函数输出C
C中的结构体和C++中结构体的不同之处:
在C中的结构体只能自定义数据类型,结构体中不允许有函数,而C++中的结构体可以加入成员函数。
C中的结构体只涉及到数据结构,而不涉及到算法,C++中的结构体和类体现了数据结构和算法的结合。
C++中的结构体和类的异同:
一、相同之处:
结构体中可以包含函数;也可以定义public、private、protected数据成员;定义了结构体之后,可以用结构体名来创建对象。
也就是说在C++当中,结构体中也可以有成员变量,可以有成员函数,可以从别的类继承,也可以被别的类继承,可以有虚函数。
二、不同之处:
结构体定义中默认情况下的成员是public,而类定义中的默认情况下的成员是private的。类中的非static成员函数有this指针,(而struct中没有是错误的,一直被误导啊,经过测试struct的成员函数一样具有this指针),类的关键字class能作为template模板的关键字 即template<class T> class A{}; 而struct不可以。
类类型转换:
#include <iostream> #include <string> using namespace std; // 使用命名空间 // 调整声明位置 class Teacher { public: friend class Student; // 设置友元,除非你用某种途径得到name,sex什么的 friend ostream& operator<<(ostream& output, Teacher t); private: long num; string name; string sex; }; class Student { public: Student(long num, string name, string sex) :num(num), name(name), sex(sex) {} // 转换应该是在Student里面,定义Teacher类型转换运算符函数 operator Teacher() { Teacher t; t.num = num; t.name = name; t.sex = sex; return t; } private: long num; string name; string sex; }; ostream& operator<<(ostream& output, Teacher t) { output << "I'm a teacher" << t.name << t.num << t.sex; return output; } int main(int argc, char* argv[]) { Student s(123, "xiaoming", "man"); cout << Teacher(s); // 强制转换直接输出 return 0; }
类模板:
如同函数模板一样,使用类模板使用户可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值能取任意类型。类模板是对一批仅仅成员数据类型不同的类的抽象,程序员只要为这一批类所组成的整个类家族创建一个类模板,给出一套程序代码,就可以用来生成多种具体的类,(这类可以看作是类模板的实例),从而大大提高编程的效率。
定义类模板的一般形式是:
template <类型名 参数名1,类型名参数名2,…>
class 类名
{
类声明体
};
例如,template <class T>
class Smemory
{…
public:
void mput(T x);
…
}
表示定义一个名为Smemory的类模板,其中带类型参数T。
在类模板的外部定义类成员函数的一般形式是:
template <类型名 参数名1,类型名参数名2,…>
函数返回值类型 类名<参数名 1 参数名 2,…>::成员函数名(形参表)
{
函数体
}
例如:template <class T>
void Smemory<T>::mput(T x)
{…}
表示定义一个类模板Smemory的成员函数,函数名为mput,形参x的类型是T,函数无返回值。
类模板是一个类家族的抽象,它只是对类的描述,编译程序不为类模板(包括成员函数定义)创建程序代码,但是通过对类模板的实例化可以生成一个具体的类以及该具体类的对象。
与函数模板不同的是:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定,
其实例化的一般形式是:
类名 <数据类型 1(或数据),数据类型 2(或数据)…> 对象名
例如,Smemory<int> mol;
表示将类模板Smemory的类型参数T全部替换成int 型,从而创建一个具体的类,并生成该具体类的一个对象mol。
#include <iostream.h> #include <conio.h> const int SIZE=8; template <class T> class Smemory { //定义类模板Smemory T data[SIZE]; //类型为T,长度为SIZE的数组data[]为数据成员 int count; public: Smemory( ){ count=0; } void mput(T x); //mput()函数的参数x的类型是T T mget( ); //声明返回值类型为T的成员函数mget() }; template <class T> void Smemory<T>::mput(T x) //定义成员函数mput(),函数的参数类型为T,该函数用于为数据成员 data数组的各个元素赋值 { if(count==8) { cout<<"Memory is full"; return; } data[count]=x; count++; } template <class T> T Smemory<T>::mget( ) //定义成员函数mget(),函数的返回类型为T,该函数用于取出数据成员 data数组的各个元素 { if(count==0) { cout<<"Memory is empty"; return 0; } count--; return data[count]; } void main( ) { Smemory<int> mo1; int i; char ch='A';//将Smemory实例化,并创建对象mo1 Smemory<char> mo2; //将Smemory实例化,并创建对象mo2 for(i=0; i<8;i++) { mo1.mput(i); //调用成员函数mput() mo2.mput(ch); ch++; //调用成员函数mput() } cout<<"Get mo1 => "; for(i=0;i<8;i++) cout<<mo1.mget( ); //调用成员函数mget() cout<<"\nGet mo2 => "; for(i=0;i<8;i++) cout<<mo2.mget( ); //调用成员函数mget() getch(); } 程序的运行结果是: Get mo1=> 76543210 Get mo2=> HGFEDCBA
类模板和模板类:
类模板的重点是模板。表示的是一个模板,专门用于产生类的模子。例子:
1 template <typename T> 2 class Vector 3 { 4 ... 5 };
模板类是类模板实例化后的一个产物,说个具体点的例子吧,我们把类模板比作是一个做饼干的模子,而模板类就是用这个模子做出来的饼干,至于这个饼干是什么味道的就要看你自己在实例化时用的是什么材料了,你可以做巧克力饼干,也可以做牛奶饼干,这些饼干出了材料不一样外,其它的东西都是一样的了。
在C++的Template中很多地方都用到了typename与class这两个关键字,有时候这两者可以替换,那么这两个关键字是否完全一样呢?
事实上class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字,它的作用同class一样表明后面的符号为一个类型,这样在定义模板的时候可以使用下面的方式了:
template<typename T>.在模板定义语法中关键字class与typename的作用完全一样。
模板类的继承包括四种:
1. 普通类继承模板类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
template<class T> class TBase{ T data; …… }; class Derived:public TBase<int>{ …… };
2.模板类继承了普通类(非常常见)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class TBase{ …… }; template<class T> class TDerived:public TBase{ T data; …… };
3.类模板继承类模板
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
template<class T> class TBase{ T data1; …… }; template<class T1,class T2> class TDerived:public TBase<T1>{ T2 data2; …… };
4.模板类继承类模板,即继承模板参数给出的基类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> using namespace std; class BaseA{ public: BaseA(){cout<<"BaseA founed"<<endl;} }; class BaseB{ public: BaseB(){cout<<"BaseB founed"<<endl;} }; template<typename T, int rows> class BaseC{ private: T data; public: BaseC():data(rows){ cout<<"BaseC founed "<< data << endl;} }; template<class T> class Derived:public T{ public: Derived():T(){cout<<"Derived founed"<<endl;} }; void main() { Derived<BaseA> x;// BaseA作为基类 Derived<BaseB> y;// BaseB作为基类 Derived<BaseC<int, 3> > z; // BaseC<int,3>作为基类 }
类模板的全特化和偏特化:
全特化:
有时为了需要,针对特定的类型,需要对模板进行特化,也就是所谓的特殊处理。比如有以下的一段代码:
#include <iostream> using namespace std; template <class T> class TClass { public: bool Equal(const T& arg, const T& arg1); }; template <class T> bool TClass<T>::Equal(const T& arg, const T& arg1) { return (arg == arg1); } int main() { TClass<int> obj; cout<<obj.Equal(2, 2)<<endl; cout<<obj.Equal(2, 4)<<endl; }
类里面就包括一个Equal方法,用来比较两个参数是否相等;上面的代码运行没有任何问题;但是,你有没有想过,在实际开发中是万万不能这样写的,对于float类型或者double的参数,绝对不能直接使用“==”符号进行判断。所以,对于float或者double类型,我们需要进行特殊处理,处理如下:
#include <iostream> using namespace std; template <class T> class Compare { public: bool IsEqual(const T& arg, const T& arg1); }; // 已经不具有template的意思了,已经明确为float了 template <> class Compare<float> { public: bool IsEqual(const float& arg, const float& arg1); }; // 已经不具有template的意思了,已经明确为double了 template <> class Compare<double> { public: bool IsEqual(const double& arg, const double& arg1); }; template <class T> bool Compare<T>::IsEqual(const T& arg, const T& arg1) { cout<<"Call Compare<T>::IsEqual"<<endl; return (arg == arg1); } bool Compare<float>::IsEqual(const float& arg, const float& arg1) { cout<<"Call Compare<float>::IsEqual"<<endl; return (abs(arg - arg1) < 10e-3); } bool Compare<double>::IsEqual(const double& arg, const double& arg1) { cout<<"Call Compare<double>::IsEqual"<<endl; return (abs(arg - arg1) < 10e-6); } int main() { Compare<int> obj; Compare<float> obj1; Compare<double> obj2; cout<<obj.IsEqual(2, 2)<<endl; cout<<obj1.IsEqual(2.003, 2.002)<<endl; cout<<obj2.IsEqual(3.000002, 3.0000021)<<endl; }
偏特化:
所谓的偏特化也称局部特化,大家大概明白什么回事了吧。 全特化是所有的模板参数都被进行特化
,偏特化也就是局部的参数特化,看看下面这个例子吧:
#include <stdio.h> #include <iostream> template<typename T1,typename T2> class A { public: A(T1 self_str1,T2 self_str2) { printf("类模板:\n"); std::cout << self_str1 << std::endl; std::cout << self_str2 << std::endl; printf("\n"); } ~A() { std::cout << "~A" << std::endl; } }; //类模板的偏特化 template<typename T2> class A<double,T2> { public: A(double t1,T2 t2) { printf("类模板偏特化:\n"); printf("double:%f\n", t1); std::cout << "T2:"<<t2 << std::endl; printf("\n"); } ~A() { std::cout << "~A:double" << std::endl; } }; //类模板的全特化 template<> class A<double, double> { public: A(double t1, double t2) { printf("类模板全特化:\n"); printf("double:%f %f\n", t1,t2); printf("\n"); } ~A() { std::cout << "~A:double" << std::endl; } }; int main() { A<int,int> a(5,6); //使用类模板 A<double,char *> b(5.0,"hello world");//使用偏特化 A<double,double> c(0.4,0.5); //使用全特化 return 0; }