C++primer 笔记

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()

你可能感兴趣的:(C++primer 笔记)