using namespace std引用的头文件写法没有.h
cout<<"$"输出ascii
cout.put("$")输出"$"
count<<hex/oct
输出为16或8进制
wchar_t bob = L'P'
wcout << L "tall"
新增bool类型
非零为true 零位false
存储小数 21.345 与2.1345
基准数相同都是0.21345缩放因子是100和10
cout.setf(ios_base::fixed,ios_base::floatfield) // fixed-point
强制类型转换
c:(int)c_wchar
C++ int(c_wchar)
long totals[500] = {0}所有元素都置0
cin 以空格作为结束的输入
cin.getline和cin.get 都是获取一行的字符,前者去掉换行符而后者不是
1
cin.get(name,Arsize);
cin.get(); // read 换行符
cin.get(dessert,Arsize);
2
cin.get(name,Arsize).get()
如果输入的的字符串比数组大会产生失效
用cin.clear()清除
string类
string str1,str2="test"
str1 = str2
str1+= str2
str[0]
struct a
{
int a;
char b[20];
}
如果想定义可以用a achar,可以去掉struct
a bchar;
bchar=achar;
struct widget
{
char brand[20];
int type;
union/struct(两种都可以)
{
long id_num;
char id_char[20];
}
}
widget prize
prize.id_num;
枚举
band=spectrum(3)将整数转为枚举
typeName pointer_nam = new typeName;
typeName pointer_nam = new typeName[10];动态数组
delete [] pointer_nam
pointername
= pointername+1 YES
arrayname = arrayname+1 NO
sizeof(arrayname) 数组大小
sizeof(pointername) 4指针大小
pointername[5] *(pointername+5)
for循环
for(int i=0;i<10;i++)
x=10
y = (4+x++)+(6+x++);
y=30因为4+x++不认为是一个完整的表达式
for(int i=0;i<10;i++)
for(int i=0;i<10;++i)
结果相同但是后者效率高
ar[2] = {1,5}
*pt = ar
*++pt 5 左结合
++*pt 2 左结合
(*pt)++ 2 右结合
*pt++ 5 右结合
可把几条语句单独放在一个独立的大括号中,并在其内可以定义变量
strcmp(str1,str2)==0 相等
strcmp(str1,str2)<0 str1在str2前面
strcmp(str1,str2)>0 str1在str2后面
cin>>h自动忽略空格和换行,并且要回车否则放到buf中
为了防止上述情况,可以使用cin.get(ch)
while(cin.fail()==false) //test for EOF
unix use the ctrl+d
while(ch=cin.get()!=EOF) cin.get返回时char型,所以先将返回转化为ch(int 型)
if(i++<6 || i==j)
如果i为10 在判断之前应为11
isdigit isalpha tolower toupper
ofstream outfile
outfile.open("fish.txt")
outfile << "ddafsfd"
outfile.close();
ifstream infile
infile.open("fish.txt")
if(!infile.is_open())
{
exit();
}
infile.close();
while(infile.good()) //while input good and not at EOF
{
++count
sum+=value
infile >> value
}
if(infile.eof())
cout << end of file reached
else if(infile.fail())
cout<< input terminate bu data mismactch
另一种方法
while(infile>>value)
{}
函数原型的功能
1 参数 数目正确?
2 参数 类型正确?
3 返回值类型正确?
const int *pint;指向常数的指针
int* const pint 指向整数的常指针
函数指针
声明 : double (*pf) (int)
区分:double (*pf)(int) 与double *pf(int)
使用:1. x=(*pf)(5) 2.x=pf(5)
int & test = t1
test 是 t1的引用,修改t1那么test也会变。他们的地址和内容都相同的
这种方法可以理解为 int *const test = &t1
int swap(int &a, int &b)
{
int r = a;
a = b;
b = r;
}
main()
{
int x=1,y=2;
swap(x,y);
}
int *p;
int swap(5,6)会为数据建立临时变量
int swap(*p,)也是可以的
引用非常适合结构和类
#include <iostream>
using namespace std;
struct reftest
{
char name[20];
int used;
};
const reftest & use(reftest &refval)
{
cout << refval.name;
refval.used++;
}
int main()
{
reftest ref1=
{
"reftest1",
0
};
use(ref1);
cout<<"ref1="<<ref1.used<<endl;
reftest ref2;
ref2 = use(ref1);
cout<<"ref2="<<ref2.used<<endl;
ref2.used = 100;
cout<<"ref1="<<ref1.used<<endl;
cout<<"ref2="<<ref2.used<<endl;
}
reftest1ref1=1
reftest1ref2=2
ref1=2
ref2=100
test(int n ,int m=5,int j=6) valid
test(int =3 ,int m,int j=6) invalid
如果定义了一个函数那么参数有可能进行类型转换,但是多个函数就没有办法进行转换了
double cube(double x)
double cube(double & x)
template 显示实例化 template swap<int>(int , int)生成一个int类型的函数
template<> 显示具体化template<> swap<int>(int& , int&) 生成与模板不同的函数
register int y
gromb(&y)这种做法不可以,没有内存地址
没有初始化静态变量,默认为0
int global=1000; // static duration, external linkage
static int one_file = 50; // static duration, internal linkage
int warming = 0.8
int main()
{
}
void funct1(int n)
{
static int count = 0; // static duration, no linkage
int llama = 0;
int warming = 0.4 //如果想访问全局变量可以使用::warming
}
struct data
{
char name[30];
mutable int access;
}
const data veep = {"Claybourne Coldde",0}
strcpy(veep.name,"test change"); //wrong
veep.access ++ //allowed
c++中全局的 const int test = 0等同于static int test = 0
extern "C" void spiff(int)
#include <new>
struct chaff
{
char dross[20];
int slag;
};
char buffer1[50];
char buffer2[500];
int main()
{
chaff *p1
p1 = new (buffer2) chaff
}
int main()
{
using Jill::fetch;
double fetch; // error already have a local fetch
cin >> fetch;
}
如果使用这种方式不会出错但会覆盖
using namespace Jill
double fetch; // 覆盖Jill里的fetch
在类声明里定义的函数,默认为内联函数
一个类声明两个对象,每个对象里的数据是独立的,但是共享方法
构造函数无返回值,也没有void
构造函数的参数不能与类成员变量同名,因此为了避免这种情况经常在成员前加m_
显示调用 stock food = stock("World",0,1);
隐式调用 stcok food("World",0,1);
指针调用 stcok *pstock = new stock("World",0,1);
有两种默认构造函数方式
1.默认参数构造
2.重载无参数
但是两个构造函数不能同时存在
stcok first("world") //接受参数构造函数
stock second() // 返回一个stock对象
stock third //调用默认构造,因此默认构造不能加括号
stock1 = stock("test")这种方式不是初始化新对象,而是建立一个新临时对象,然后将新的临时对象
成员付给老的对象中,随后调用临时对象中的析构函数将其销毁
const stock land = stock("world")
land.show() //这种使用方式不合法,因为不能保证show是否修改land中成员变量
用一下方法可以做到
void show() const
void stock::show() const
只要不修改成员变量成员函数最后定义成这样
const stock & stock::topval (const stock & s ) const //第二个const表示显式参数为常量,第三个是隐式
//不被修改
{
if(s.total_val > total_val)
return s;
else
return *this;
}
stock stock[10] = {
stock("world"), //构造函数
stock(), //使用stock()构造,后8个用默认构造
}
class stock
{
private:
static const int len;
}
操作符重载
Time Time::operator+ (const Time & t) const
{
Time sum;
...
return sum;
}
不可以重载
**
sizeof
.
.*
::
?:
typeid
const_cast
dynamic_cast
reinterpret_cast
static_cast
只能通过成员函数进行重载
=
()
[]
->
Time Time::operator* (double t) const
{
Time sum;
sum.t *= t;
...
return sum;
}
如果 t = t1*1.5 可以
但是 t = 1.5*t1就是非法的。解决这种办法是使用非成员函数
Time operator* (double m,const Time &t),不过有个问题如何使用类成员变量
使用友元函数,在类中声明如下
friend Time operator* (double m, const Time & t)
定义:
不用加前缀类名
void operator << (ostream &os,const Time &t)
{
os << t.hours << "hours" << t.min << "min";
}
在类定义里将这个函数定义为友元
可以完成以下效果
cout<< time
但是如果我想拼接输出怎么办?
ostream & operator << (ostream &os,const Time &t)
{
os << t.hours << "hours" << t.min << "min";
return os;
}
就可以count << "asdfd " << time
Stonewt myCat
myCat = 19.6
这种方法可以,因为这个对象的定义构造函数为 Stonewt(double lbs)
过程是将建立一个临时对象然后复制到myCat中.
但是如果不想使用这种功能可以使用关键字 explicit Stonewt(double lbs)
不过还是可以显示转换
1 myCat = Stonewt(19.6)
2 myCat = (Stonewt)19.6
那反向可以吗?即:double t = (double)myCat,double t = double(myCat)
必须定义 Stonewt::operator double() const
Stonewt jennyst(9.12)
double pennyD = 146.0
Stonewt total
total = jennyst + pennyD
以上调用的只能定义+为友元的方式才可以实现
static const int len;
不能在类声明中初始化静态成员变量,但可以在类声明之外单独进行初始化。整形和枚举是列外
如果没有定义,编译器会为你默认定义一下四个函数
1 默认构造函数
2 复制构造函数
3 赋值操作符
4 默认析构函数
5 地址操作符
以下4中情况调用复制构造函数,motto也是StringBad
StringBad ditto(motto);
StringBad metoo = motto;
StringBad also = StringBad(motto);
StringBad * pStringBad = new StringBad(motto);
默认构造函数逐个复制非静态成员的值,如果成员是另一个对象,调用另一个对象的复制构造函数
复制构造函数的原型是:StringBad::StringBad(const StringBad & st)
StringBad metoo = motto;
这个操作也可能是:复制构造创建一个临时对象,然后通过赋值将临时对象的值复制到新对象中
注意:在以上复制构造或赋值操作里都要注意,如果有成员需要用new的时候,要考虑深拷贝,防止在析构
时用delete而出现重复删除
静态成员函数
static int HowMany {return num_strings;}
int count = String::HowMany();
pc1 = new(buffer) JustTesting;
pc2 = new(buffer + sizeof(JustTesting)) JustTesting
new后的buffer地址在申请的时候要变的,否则会出现内存申请错误
释放过程要显示的调用析构函数
pc1->~JustTesting()
pc2->~JustTesting()
delete [] buffer
Queue::Queue(int qs) : qsize(qs)
{
}
将qs付给qsize,这种方法赋值常量或构造函数的参数列表中的参数,常量和被声明为引用的类
成员必须用这种方法,因为它们都是被创建时初始化
子类在调用构造函数时,先调用父类的构造函数。如果父类没有构造,就调用默认构造
应通过成员初始化列表将基类信息传递给基类的构造函数如:childclass::childclass(typename t1):bass(t1)
派生类过期后先调用自己的析构,在调用基类的析构
基类引用和指针可以不进行显示类型转换的情况下使用派生类
RetedPlayer rplayer();// base class
TableTennisPlayer & rt = rplayer;
TableTennisPlayer * pt = &rplayer;
但是不可以用rt或pt访问派生的方法
同时,不可以将派生类的指针指向基类
这种方法常用在参数传递。
1 Brass dom("Dom",1243,43543); // bass class
2 BrassPlus dot("Dot",435,48763); // child class
3 Brass &b1_ref = dom;
4 Brass &b2_ref = dot;
5 b1_ref.ViewAcct();
6 b2_ref.ViewAcct();
如果ViewAcct不是virtual函数,那么5和6调用的都是基类的ViewAcct。如果是virtual访问的就是
基类和父类的函数
因为这种方法也会影响到析构函数,因此析构函数也应该定义virtual
virtual函数是在动态联编,又称晚期联编
虚函数的工作原理
1 在每个对象中建立一个虚拟函数的地址表
2 在使用的时候才动态去虚拟函数的地址表中查找出对应函数的地址
只有类成员才能使虚函数,因此友元不能是虚函数
构造函数定义为protected,并没有公有构造,可以防止局部实例被创建
只能定义静态成员
virtual double Area() const = 0//纯虚函数
包含这个函数的类是一个抽象基类
使用new delete时需要的特殊方法:析构函数、复制构造函数、重载赋值操作符
派生的类的友元如何访问基类的成员呢?
将派生类强制转化为基类
如果函数返回的是在函数内部生成的临时变量对象,则应该返回对象
如果函数返回的是在函数参数传递进来的,则应该返回对象引用
double gpa[5] = {3.1,3.5,3.8,2.9,3.3}
valarray<double> v1 // an array of double , size 0
valarray<int> v2(8) // an array of 8 int elements
valarray<int> v3(8,10) // an array of 8 int elements, each set to 10
valarray<double> v4(gpa,4) // an array of 4 elements,init to the first 4 elements of gpa
explicit 防止单参数构造函数的隐式转换
可以使用初始化列表初始化一个额外的对象
私有继承就是基类的公有成员和保护成员成为私有成员。相当于has-a关系
私有继承如果想访问基类的方法可以通过 ArrayDb::sum()这种方法,当然在构造派生的时候要构造
基类
如果想访问私有继承的基类怎么办?
用强制转换
如:
const string & Student::Name() const
{
return (const string &) *this;
}
Student派生类私有继承了String
注:友元也可以使用这种方式
保护继承是将基类的公有和保护成员变为派生类的保护成员
如果想要让对象使用私有派生类里面的的方法有两种:
1 定义一个额外的接口函数,在函数内部调用私有方法
2 使用using std::valarray<double>::min
多重公有继承必须指定每个基类是public
多重继承可能出现的问题:
1 从两个不同的基类继承了同名方法
2 从两个或更多基类那里继承同一个类的多个实例
多重继承
基类worker 派生出两个类singer 和 waiter 再从这两个类派生出一个SingerWaiter
当用基类worker指针指向SingerWaiter时会产生冲突
解决方法采用虚基类:派生出的对象只继承一个基类对象
class singer:virtual public worker{}
class singer:public virtual worker{}
class A
{
int a;
public:
A(int n = 0){a = n;}
}
class B:classA
{
int b;
public:
B(int m=0,int n = 0):A(n){b = m;}
}
class C:classB
{
int c;
public:
C(int q=0,int m=0,int n = 0):B(m,n){c = q;}
}
C的构造函数调用B的构造,在调C的构造。同时通过初始化列表。
但是虚基类就不能通过这种方式
比如C(int q=0,int m=0,int n = 0):B(m,n)就要用
C(int q=0,int m=0,int n = 0):B(m,n),A(n).但是这样的用法在非虚基类的情况下是非法的
worker中有派生类singer和waiter这两个类中分别有show方法,如果SingerWaiter没有show方法
这时通过什么来区分是哪个基类的show方法呢?
singerwaiter.singer::show()
模板类
在模板类声明的时候加上template <class Type>把需要替换的类型替换到type
定义如下:
template <class type>
stack<Type>::stack()
{}
stack<String> st
template <class T,int n>这种方法可以用在数组上面,指定数组大小
模板类型嵌套相当于多维数组
ArrayTP<ArrayTP<int,5>,10>
template <class T1,class T2> m1 //多模板参数
template <class T1,class T2 = int> m2 // 默认类型模板参数
友元类可以访问其类的保护和私有成员
友元成员函数
class TV
{
frind void Rommote::set_chan(TV &t,int c)
}
class TV
class Remote{}
class TV{}//因为要引用Remote中的函数
但是Remote中有方法又调用了TV,如:void onoff(TV &t)
把Remote的函数做成inline
嵌套类Queue::Node::Node(const Item & i):item(i),next(0){}
嵌套类作用域与其他变量一样也分私有、公有、保护
abort可以终止程序
test()
{
if(t == 1)
throw "this is test file";
}
try
{
test();
}
catch(const char *s)
{
cout<<s;
}
test()也可以在后面加上test() throw(classname)
exception类可以作为其他异常类的基类
可以重写虚拟函数what()