void fa(int x)
void fb(int & x)
void fc(const int & x)
fa(x);fa(y);fa(100);//fa因为是值传递,所以是可以的。
fb(x);//fb(y);//fb(100);此两个都为ERROR,因为是引用,fb(y)不能将const的引用传递给非const,因为这样程序可能对y值做改变,会改
变一个const值,系统是不允许的。100相等于const值。
fc(x);fc(y);fc(100):都正确。
总结:高限制级别的不可以向低限制级别的赋值,低限制级别的可以向高限制级别的赋值。
命名空间相当于全局变量,但是使用时要加using namespace ***,然后在下面就可以用了,或者***::名字。若向其中加函数,直接namesapce
***{函数名},命名空间不允许在函数中(包含 main 函数中定义)。使用using namesapce ***是声明下面使用的都是 *** 中的内容,如
果 *** 中的内容和全局变量一样,则系统会产生歧义,分不清到底是哪个。
int * p = reinterpret_cast<int *>malloc(40); p = new int(40);delete p; p = new int[35];delete []p;
C++中,fa(void)=fa(); ff(int){}哑元参数。
C++提供了四种新的类型强制:
static_cast,const_cast,reinterpret_cast,dynamic_cast
an = static_cast <CAnimal> (jean);//将对象jean强制成CAnimal类型
const_cast类型强制将一个const变量变成一个非const的等价形式
reinterpret_cast运算符用来将一个类型指针转变为另一种类型的指针,也用在将整型量转为指针,或将指针转为整型量上
常量相当于const类型的数据,int &fa(int &x){return x;}//这种情况是可以的。int &fa(int x){return x;}//返回一个局部变量的引用,
会有问题的。当返回值为引用时,此函数可以做左值。
引用在定义的时候就要初始化。
int x = 10;int &r = x;int y = 20;r=y;//相等于x = y(此时x中值是20).
构成函数重载的条件(overload):函数名相同,参数列表不同(参数个数不同,参数类型不同,参数顺序不同,和返回值没有关系。函数名
加一个const也可以构成overload).实现函数overload时,系统是给函数都起了不同的名字,如果overload的函数前面加上 extern "C"时,
因为都是同样的名字,系统会分不清具体调用时用哪个函数,所以不能加 extern "C".
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <time.h>
using namespace std;
class Time{
int h,m,s;
public:
Time(int h=0,int m=0,int s=0){this->h=h;this->m=m;this->s=s;}
void show();
void run();
void tick();
};
void Time::tick()
{
s++;
if(s==60) {s=0;m++;}
if(m==60) {h++;m=0;}
if(h==24) h=0;
}
void Time::run()
{
while(1)
{
show();
time_t tt = time(NULL);
while(tt == time(NULL));
tick();
}
}
void Time::show()
{
cout<<setfill('0');
cout<<setw(2)<<h<<":"<<setw(2)<<m<<":"<<setw(2)<<s<<flush<<'\r';
//cout<<"hello"<<endl;
}
int main()
{
Time t(3,1,3);t.run();//t.show();
}
若类中有成员变量const类型和引用类型,只能用():这种方法初始化。不允许在类中直接初化成员。
默认值要从右向左给,默认值并不能解决函数overload问题,不过当用默认值能解决时,优先用默认值。
普通函定真正会实现内联。
Emp *pe = Emp(1,"abc");
void show()const 只读函数不能改变成员变量的值,只能改变mutable类型的成员变量。只读函数和非只读函数可以形成
overload关系。
const Emp e1 e1.show()
const成员变量不可以修改其值。
const变量只能调用const成员函数
为了防止调用拷贝构造函数时再次构造新的对象,copy要加引用。 Emp(const Emp &e).
就算是人为的调用 Emp e; e.~Emp(),并不能真正释放此对象,它只是调用了一个函数,系统仍会调用析构函数,来释放资源。
static 变量在类中只有一份,因此当在一个对象中对其变化时,其它变量中的此static变量也会改变,static函数只能调用static
成员变量,static成员函数中没有this指针,因为它不属于哪个具体的类。
类中成员函数相互调用,不需要声明。
静态成员也受到类的访问范围的限制。
const类型的成员变量只能应用const成员函数。当有const类型的成员变量时,必须在构造函数中对其赋值。
当一个类中有指针时,必须要人为的重写构造、赋值、copy构造、operator=,析构操作符。
friend ostream &operator<< ( ostream & o,const fenshu &f);
friend istream &operator>> ( istream & i, fenshu &f);
对>>和<<重载时,不能加 const
cout<<&x<<endl;cout<<&(++x)<<endl; 这2个值打印出来是一样的。
名字隐藏:只要子类中有和父类中名字相同的函数,则父类中的函数就被隐藏起来,与函数参数和返回值没有关系,要想把父类中
函数调出来,用 父类::函数名 就可以做到。
构造函数时,先递归构造父类,再构造成员函数,再构造自己,析构时顺序正好相反。
operator int(){return x;}
operator CInterger(){return x;}
当做类型转换操作重载时,最前面没有返回类型值。
构造函数也有类型转换功能。如果加了 explicit ,在只有一个成员变量的构造函数中,构造函数不能做隐式转换。
虚继承例子: phone::Goods mp3::Goods camera::Goods CellPhone::phone,mp3,camera. 可以让phone mp3 camera中的任何组合虚继承Goods,要在最终子类中直接给虚继承的类构造,虚继承类在最终COPY中只有一份。可以通过 子类名::函数名将隐藏的函数调出来。
class A{
int x;
public:
A(int x=0):x(x){cout<<"A construct"<<endl;}
~A(){cout<<"A deconstruct"<<endl;}
void * operator new (size_t sz)
{
cout<<"void * operator new (size_t sz)"<<endl;
return malloc(sz);
}
void * operator new[] (size_t sz)
{
cout<<"void * operator new[] (size_t sz)"<<endl;
return malloc(sz);
}
void operator delete[](void *p)
{
cout<<"void operator delete[](void *p)"<<endl;
delete []p;
}
void operator delete(void *p)
{
cout<<"void operator delete(void *p)"<<endl;
delete p;
}
};
int main()
{
A * pa = new A;
delete pa;
A *ppa = new A[3];
delete []ppa;
return 0;
}
explicit cls(int x=0):x(x){}以后,只有一个数据成员的类就不能直接用整数来赋值了。
虚继承:
class CAnimal{
public:
void eat(){cout<<"Animal eat"<<endl;}
void sleep(){cout<<"Animal sleep"<<endl;}
virtual void run(){cout<<"Animal run"<<endl;}
};
class CDog:public CAnimal{
public:
void eat(){cout<<"CDog eat"<<endl;}
void sleep(){cout<<"CDog sleep"<<endl;}
virtual void run(){cout<<"CDog run"<<endl;}
};
int main()
{
CAnimal *pAnimal = new CAnimal;
pAnimal->eat();
pAnimal->sleep();
pAnimal->run();
return 0;
}
动物指针指向动物对象,动物吃 动物睡 动物跑
动物指针指向狗对象 动物吃 动物睡 狗跑
狗指针指向狗对象 狗吃 狗睡 狗跑
狗指针指向动物对象 会有问题的。
指针指向的对象是哪个,就调用哪个的虚函数覆盖的函数,如果没有覆盖,就调用基类的。
静态绑定,编译期绑定。动态绑定,运行期绑定。
class DB{
virtual bool connect()=0;
virtual bool execsql()=0;
};
DB为一个抽象类,抽象类不能定义对象,只能被继承.一个类中含有纯虚函数时,也不能定义对象.
当有子类继承时,可以不实现这个纯虚函数,但是这个子类因为也含有纯虚函数,所以也不能定义对象.
当子类中实现了这个纯虚函数时,子类就可以当作普通类使用了.
当有纯虚函数时,必须要实现它,否则不能定义对象.
子类继承父类时,不能抛出的异常比父类更多,不然会报错(只存在于虚函数中,如果不是虚函数,无所谓).
函数原型 throw():表示不抛任何异常,异常处理时,const char *和char*是不同的.
在main函数中不能再抛出异常,throw()后的程序不会再执行. throw(int)----catch(int x).
try{有异常抛出的代码} catch(异常类型) {对异常的处理,throw(此函数抛出的异常);}
函数后面的 throw(const char *)不能写成throw(const char * e)不然会编译通不过.
main中是最终的处理,不能再抛了.
一个异常的例子:
class BankException{
};
class QunException:public BankException{
private:
int x;
public:
QunException(int x=0):x(x){}
};
class QuException:public BankException{
};
void cunqian()throw (QunException)
{
cout<<"cunqian"<<endl;
throw QunException(7);
cout<<"after cunqian"<<endl;
}
void quqian() throw (QuException)
{
cout<<"quqian"<<endl;
throw QuException();
cout<<"after quqian"<<endl;
}
int main()
{
cout<<"main begin.."<<endl;
try{cunqian();quqian();}
catch(BankException & e){cout<<"catch BankException"<<endl;}
catch(QuException & e){cout<<"catch QuException"<<endl;}
try{quqian();}
catch(BankException & e){cout<<"catch BankException"<<endl;}
catch(QuException & e){cout<<"catch QuException"<<endl;}
cout<<"main end.."<<endl;
}
/*
程序运行结果:
main begin..
cunqian
catch BankException
quqian
catch BankException
main end..
*/
dynamic_cast转换只能用于有虚函数的类,有虚函数的类才可以进行这种转换.如果没有虚函数,进行这种转换,在编译的时候会报错的.当转换后为一个指针时,如果转换不成功,此指针为null,如果转换为引用转换,会抛出 bad_cast 异常.
ifstream(作为cin看待) ofstream(cout)
#include <fstream>
int main()
{
ifstream ifm("a.txt");//同cin一样的用法
ofstream ofm("b.txt");//同cout一样的用法
char c;
while ((ifm>>c))
{ofm<<c;}
ofm.clear();
ifm.close();
ofm.close();
}
在ios中有对格式的具体的说明.
ofstream ofm("a.txt");ofm.write()
ifstream ifm("a.txt");ifm.read()
ostream::seekp ostream::tellp ostream::put
istream::tellg istream::seekg istream::get
文件内置有输入文件指针和输出文件指针,当用fstream时,这两个是一样的,移动输入文件指针,输出文件指针也变,输入文件指针变化时,输出文件指针也变.如果分别是 ostream和 istream,是不同的.
istream& ignore( int nCount = 1, int delim = EOF ); 在istream中清除nCount个字符,直到遇到delim为止.
ios::clear( int nState = 0 ); 清除 nState 标志.
C++标准要求,cin cout等输入输出对象在正常情况下返回逻辑真,出现问题时返回逻辑假,当它们出现问题时就拒绝工作,此时要让它们恢复成正常状态才可以继续工作.
cin.clear()清除错误标志,不会清缓冲区. cin.ignore(100,'\n')清除缓冲区.
在函数中用new在堆上分配空间,可以在main函数中释放此空间.
cerr cout clog
在kate中 ctrl+d 将一行注释起来.
stringstream ssm(一个string的字符串). istringstream ostringstream ssm.str()此流中的数据
typeid主要用在多态情况下,获取一个父类指针或引用指向的对象具体的类型信息. typeid()返回值为 const type_info& . name()
虚函数表:
class A{
int x;
public:
void show(){cout << "A" << endl;}
};
class B{
int x;
public:
virtual void show(){cout << "B" << endl;}
virtual void show1(){cout << "BB" << endl;}
};
class C : public B{
public:
virtual void show(){cout << "C" << endl;}
virtual void show1(){cout << "CC" << endl;}
};
class D : public B{
public:
virtual void show(){cout << "D" << endl;}
virtual void show1(){cout << "DD" << endl;}
};
int main()
{
A a;
B b;
cout << sizeof(a) << endl;//4
cout << sizeof(b) << endl;//8
a.show();//编译期//A
b.show();//运行时查看虚函数表来确定调用哪个函数//B
B* pc = new C;
B* pd = new D;
pc->show();//C
pd->show();//D
pc->show1();//CC
pd->show1();//DD
memcpy(pd, pc, 4);
pd->show();pd->show1();//C CC
}
//每个有虚函数的类除了自己的成员变量外,还有一个指针,此指针指向虚函数表,(v_table).
//在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反应实际的函数
//虚函数表的指针存在于对象实例中最前面的位置
//运行时查看虚函数表来确定调用哪个函数
#include <iostream>
#include <cstring>
using namespace std;
class B{
int x;
public:
B(){cout<<"B construct"<<endl;}
/*virtual*/ ~B(){cout<<"B deconstruct"<<endl;}
virtual void show(){cout << "B" << endl;}
};
class C : public B{
public:
C(){cout<<"C construct"<<endl;}
/*virtual*/ ~C(){cout<<"C deconstruct"<<endl;}
virtual void show(){cout << "C" << endl;}
};
int main()
{
B *pb = new C;//如果析构函数不为虚,结果为 B construct/ C construct/ B deconstruct
//如果析构函数为虚函数,则为 B construct/ C construct /C deconstruct / B deconstruct
delete pb;
}
//当类中有虚函数时,要保证析构函数也有虚函数,才能确保分配的对象正确释放.
#include "stdafx.h"
#include <iostream>
#include <string>//getline函数的头文件
using namespace std;
int main()
{
char ch1, ch2, ch3, ch4;
ch1 = cin.get();
cin.get(ch2).get(ch3).get(ch4);
cout << ch1 << ch2 << ch3 << ch4;
cout.put(ch1).put(ch2).put(ch3).put(ch4);
char str[100];
cin.getline(str, 100);//成员函数
cout << str << endl;
string str2;
getline(cin, str2, '#');//全局函数
cout << str2 << endl;
}