C++基础语法

来源:互联网 发布:js判断质数的算法 编辑:程序博客网 时间:2024/06/06 14:27

第一章:

1,面向对象程序设计的有点:

实现对现实世界客体的自然描述。

可控制程序的复杂度。

可增强程序的模块性。

可提高程序的重用性。

可改善程序的可维护性。

 

 

第二章:

1,cin -> stdin; cout -> stdout; cerr->stderr;clog->stdprn,cerr和cout的区别就是他不能够被重定向。

2, 命名空间的声明 namespace mfc {int inflag;} 同一个命名空间可以定义多次。

using 用多了会冲突。

3,cin>>x>>n,这个输入到x,n主要是通过空格来隔开的。也是通过空格表示结束。

4,dec 十进制, oct八进制,hex十六进制,cout<<hex<<i<<endl;一旦进入这个状态就不能改变了。例如,cout<<hex<<i<<endl; cout<<i<<endl; 两个都是十六进制。

5,setw如果不够大小的话不起作用,如果比原来的大的话从左边填充。setw是一次性的,就是说如果输出了,就不会见效了,必须重新来。例如,cout<<setw(3)<<3456,这个不会扩大,而cout<<setw(7)<<3456就会左边填充空格,之后cout<<3456又回到wide = 0的默认值了。这个东西是iomanip文件中的,需要include <iomanip>

6,setprecision()这个在double地时候是表示留下几位。例如,33.33 setprecision(2), 33.3,如果有fixed,就是小数点固定,就表示小数点后面几位的。例如,33.3333 fixed + setprecision(2) 为33.33 表示小数点之后的留下几位。

7,ifstream fstr(path) ofstream istr(path)

8,const int* a 这个表示所指向的内容不会变。int* const a 表示指针a不能变。

9,float j = static_cast<float>(i). const_cast<int> 把const转化成为不同的。

if(typeid(*base) == typeid(Derived1)) {

    Derived1 *derived1 = static_cast<Derived1*>(base);

    derived1->showOne();

}

static_cast和dynamic_cast就是都是通过是基类转化成为派生类。但是static就是强转化,而dynamic_cast是弱转换。如果失败会跑出bad_cast的异常。

如果device& x, dynamic_cast<deviceBase&>(x)....需要注意引用的应用。这里面需要注意的是dynamic_cast<D> D 一定是引用和指针。

reinterpret_cast用于不同类型的转换。 

10,bool的地方也可以用Int是否等于0来判断。-1也是true。

11,string是以NULL为结尾的。string s4(10,'X'); string s3 = s2; int 转化成为string 用<sstream>中的stringStream,因为是流.例如:

string str;

stringStream strStream;

int i = -1;

strStream<<-1<<endl;

strStream>>str;

cout<<str<<endl;

 

12,遍历文件夹getline

#include <string>

#include <file>

using namespace std;

 

int main(char* args[])

{

string str;

ifstream input("C:\\source.txt");

ofstream output("C:\\dest.txt");

while(getline(input,str))

{

output<<str;

}

input.close();

output.close();

}

这里需要注意,file的空间和getline的返回。

 

13,erase(开始位置,长度);insert(插入位置,插入的字符串);replace(替代位置,子窜大小。子串。),swap(字串),find("",startPos), 字符串支持 == > < != 这样的操作。

 

14,int main(int argc,char * argc[]){...}

15, 引用,一般都是用于参数传递的时候用,这样能够对这个参数进行修改。不能然会局部变量的引用。

16,inline函数的限制:

a,不能包括复杂的结构控制语句(while, switch)。

b,不能包括内联函数本身。

c,不能是直接递归。(自己内部还调用自己的函数)

17,inline和宏的区别:

a,宏是预处理器进行替代,而inline是编译实现的。inline有更强的约束性。

b,inline函数是真正的函数,是准寻函数类型和作用与规则。

注意:类中的inline函数一般都是在.h文件中直接定义。

18,函数签名不包括返回值,所以不能只看返回值。

19,函数的默认参数必须从右边开始。

20,

 

第三章:

1,C++中class 的默认的作用域和private是一样的。而struct的默认的是public一样的。

2,inline在类里面,如果在.h生成的就是内联函数。如果是分开定义的,那么就在.h定义这里面加上inline字符就可以了(注意cpp不要加。)

3,

成员函数+const 就是让属性值不要减少。 例如:GetValue() const{return this->a;} 这里a不能有。

而且这里面不能够调用non_const的成员函数。

4,如果函数返回类型采用const的话,那么,只能赋值给一个const类型的局部变量。

5,

对象数组,当调用对象数组的时候,会默认调用每个对象的构造函数。C ar[1000] 会调用1000次构造函数。如果没有够着函数,会默认生成一个默认的。

如果有了一个公有的,就不会生成默认的。

默认的够着函数,里面的类成员不能被初始化。

6,

拷贝构造函数:Person(Person& person)和Person(const Person& person),拷贝构造函数可以有多个参数,但是这些参数必须有默认值。

当函数中有一个属性指向了动态存储空间的时候,应该调用拷贝构造函数。默认的只是直接赋值,这样,两个对象的指针就指向同一个对象了。如果命名了拷贝构造函数的话,就不会有默认的了。

这个时候,如果把这个拷贝构造函数放在私有,这样就禁止了拷贝构造函数。

7,转型构造函数,里面要用到一个explicit。可是实现隐形转换。

8,初始化够着函数列表。Person():x(1),y(0),而且const只能通过这来初始化。

9,类静态成员的声明,int C::s = 0;而且如果没有用static标明,不能够在函数中声明。

10,const 对象不能够调用成员函数,主要是因为这样能够改变这个类里面的值。

 

第四章:

1,C++ 支持多重继承,就是一个类可以同时继承多个类。

2,通过using可以在子进程中改变基类的控制范围。例如:

class BaseClass

{

public:

BaseClass(int value);

int GetValue();

void SetValue(int i );

private:

int value;

}

class derivedClass: public baseClass

{

public:

DerivedClass(int a ,int b):BaseClass(a),valueB(b);

void SetValue(int i);

private:

using baseClass::GetValue;

int valueB;

}

3,如果继承之后新成员(成员函数,成员变量)名称(只同名就可以)和基类的同名,他将会覆盖这个老成员函数。其实也无所谓隐藏,BaseClass::SetValue()和DerivedClass::SetValue()来区别的就行了。

4,在公有继承的方式下,保护成员是能够被子类看到的。

5,构造函数和析构函数是不能够被继承的。当派生类没有自己的构造函数的时候,会直接调用父类的默认构造函数。如果没有声明,在调用自己的初始化构造函数的时候,调用父类的初始化构造函数。

例如上面的类:如果子类没有构造函数而父类有,这样的话,父类的构造函数必须有默认构造函数。其实就是说,如果要是显示调用了基类的构造函数的话,就不需要了。如果要是没有显示,需要父类有一个默认构造函数,子类会调用。

6,析构函数的工作和构造函数的调用顺序正好相反。而且,析构函数每个类至多只有一个。

7,类成员初始化的顺序取决于他在被继承时所说明的顺序,并非初始化队列的顺序。

8,多重继承的时候,如果两个基类有同名的函数,这样的话就会发成冲突会出错。

多继承的构造函数顺序,基类的构造函数先被调用,数据成员所在类的构造函数次之,最后指向派生类的构造函数。这个其实就是因为构造函数的时候先执行父类的,然后才是属性复制,然后才是当前的构造函数。

9,虚基类,当多重继承的时候。例如:

class C : D1,D2

{

 

}

class D1: B

{

 

}

class D2: B

{

 

}

class B

{

public: int x;

}

这个时候当生成C的时候,会生成两个B class的副本(内存里面是两个B的对象),这个时候,如果 C.B::x = 2; 是有问题的,因为这个时候并未指明是哪个B 的副本。而且,当你调用C.x的时候也有二意性。C.D1::x 和 C.D2::x不是一个值。但是,如果上面的全都是弄成虚基类。也就是如下:

class D1 : virtual B

class D2: virtual B

这个时候就只有一个副本了,C.B::x =2 只有一份,不会有歧义。C.x也是。还有虚基类的构造函数最先调用。

10,继承分为三种继承:

公共继承,公有的-》公有,私有的—》不可访问,保护的-》保护

私有继承,公有的-》私有,私有的—》不可访问,保护的-》私有

保护继承,公有的-》保护,私有的—》不可访问,保护的-》保护

11,类型适应:派生类的对象,引用,指针都可以赋值给基类的。

 

第五章:

1,虚函数这个东西,需要在基类上面定义virual函数,子类如果不定义也可以(不定义回去找同名的),定义更好。虚函数的主要目的在于动态绑定,如果不是虚函数,那就是对象是什么就调用什么,而如果是虚函数,就是调用真正的。如果在外面定义的函数,只需要在生命时候加上virtual就可以了。

例如: Base a; Derive b;

a = b;

a.print(); 如果print是虚函数,调用的就是b.print,如果不是调用的是a.print。

现在有这么一个例子:

Class Base{ 

void Act1(){Act2();}

void Act2(){cout<<"ori act2"<<endl;}

}

class Derive:public Base

{

void Act2(){cout<<"dest act2"<<endl;}

}

 

Derive b; b.Act1(); 输出是? 

 

ori act2

 

如果把Act2 变成虚函数,这个时候结果就是 dest act 

 

这里主要是因为这个时候this指针已经多态了,你可以把this看成 Ori* source = new Derive();

2,析构函数可以是virual的。只要加了virtual,派生类的就都不需要加了。vitual析构函数的作用是delete 子类的时候(但是这时候是动态绑定,内容是子类的,表表面是基类的),会调用子类的析构函数,之后还会调用父类的析构函数。如果要是没有virtual,动态绑定的时候,对不会调用子类的析构函数。如果是其他函数,如果派生来加上了virual就是说它现在也是虚函数,下面的人可以覆盖。

3,静态成员函数不可以是虚函数。

4,重载:就是同一个类,两个不同样签名的函数。---》编译绑定

覆盖:基类子类,虚函数,两个同样签名(不含返回值)的函数。---》动态绑定

隐藏:基类子类,不是虚函数,函数名字相同就行。 ---》编译绑定

如果虚函数,如果不产生覆盖(在只有函数名字相同的时候),就会产生隐藏。

5,纯虚函数主要是的写法是: virtual void open() = 0; 又纯虚函数的类不能够产生对象。

6,在#include <typeInfo> 中typeId()

也就是typeid(对象,引用,指针) == typeid(类,引用,指针) 例如class A;... A a; if(typeid(a) = typeid(A)){cout<<"TRUE"<<endl;}

7,动态函数中调用虚函数,搜现实调用自己类实现的,如果自己类没有实现,就调用基类的虚函数。不会调用其他派生类的。

 

第六章

1,不能被重载的运算符:?: . * ::;除了=之外,其他的都可以被派生类继承。操作符重载不改变优先级和集合率。

2, 顶层操作符重载在定义的时候必须就不是相类成员一样了。他就没有默认的类对象当做参数。而且必须明确的指出来。

例如,C operator+(const C&c, const C& c2) 这个主要就是 Cresult = c + c2;

并且,对于顶部操作符重载,我们需要用到一个自定义个类。如果要是没有的话,区分不了。

这样的操作都是顺序的,例如:C operator[](Point& s , int i)就是 s[i]这个样的一个东西。是有先后顺序的。

对于二次型操作符,与使用类成员函数相比,只要定义了可转型的构造函数,使用顶层函数进行重载是可以不用在乎左右两边的。如果用类的话,第一个参数必须是类对象。(恶心:()

3,友元函数其实很简单,就是在一个类里面的方法的前面加上friend,放在public,protect,private都可以,反正不是这个类的函数。这样在外面定义的时候不需要加上friend,这个时候这个函数就能够访问这个类的私有和protect的变量的。例如:

class A

{

public:

void Print();

friend void PrintOut();

friend B::PrintA();

friend C;

private:

int a;

}

 

class B

{

public: 

void PrintA();

}

 

class C

{

public:

void PrintA()

{

cout<<a<<endl;

}

}

 

void B::PrintA()

{

cout<<a<<endl;

}

 

void PrintOut()

{

cout<<a<<endl;

}

如上面,友元可以为一个类,一个类的成员函数,一个顶层函数。但是,我们只建议在顶层操作符的时候使用。

3,>>的操作符重载,这里一般第一个参数一般都是istream的引用。返回的也是。

()函数操作符的重载,double operator()(double x,double y) const { return x*2 + y;} ,这个就是f(1.5,3.2);

counter operator ++(); 前缀操作符 counter operator++ (int); 后缀操作符,后面的int就是为了表明是后缀操作符。

 

第七章

1,模板这东西其实是编译程序会根据函数调用的实际情况把T所代表的类加载进去。所以,如果T出了问题编译是不能通过的。

函数模板在应用的时候,不要用<>来制定类型,他会直接通过传入的参数类型直接定义T的类型。例如:

template<class T>

T Sum(T a,T b)

{

return a + b;

}

void main()

{

int sum = Sum(1,3);

}

2, 模板这个东西的格式比较好玩,就是生命的时候呢,类用永远和《T》没关系,但是在定义的时候<T>一定要制定了。而且,在它用于当做作用域的时候也需要制定。这个函数就不是了,模板函数不需要指定。例如,

template<class T, int i>

class A

{

public:

T a;

T Get_a_Value();

}

 

template<class T,int i>

T A<T,int i>::Get_a_Value()

{}

 

void main()

{

A<int,5> a;

int i = a.a;

}

而且还有一点需要注意,就是当你声明template的类时候,这个类的方法好像必须定义在.h文件当中。

3,这里还有一个值得注意到地方,不同T的template类是完全不同的两个类,例如上面的A<int,3>和A<int 4>;A<double,1>和A<int,1>;不是一个类型,所以他们不可能拥有同一个基类,同一个静态变量。而A<int,4>和A<int,4>的对象就是一样的。

4,STL包括容器,算法,迭代器,函数对象,适配器,配置器。

5,迭代器就是一个封装了的指针,指向一个容器的每个数值。他重载了*符号,访问他说指向的值。还有他重载了++运算法。可以移动。

有向前迭代器和向后迭代器,向前就是++向前,而向后就是++向后移动。还有,他有const不const,如果是const表明不能够改变iterator的值。

6,list -> 双向链表 

vector -> 可以伸缩的数组

deque -> 两端进行有效插入删除的数组。

set 不含重复值的集合

map 键值不可以重复

multiset 允许重复值的set

multimap 允许重复键值的map

 

vector 适合在尾部插入删除的操作,deque适合两边插入删除的操作。

list不能够通过下标访问。

 

7,stack,queue, priority_queue: stack,queue默认派省委deque;priority_queue默认为vector

stack<char> s;默认 stack<char,vector<char>> s

 

8,bitset记录二进制,bitset<8> bs  --8位0 bitset<8> bs(9) --8位表示9

 

其他积累:

1,C++中没有finally,必须用try catch来搞定,或者用对象控制。

2,C++中最好不要用两层的调用。例如:a.b.c.size();

3,类的参数初始化在.h文件中就行。

4,typeid 是<typeinfo> 命名空间的。 dynamic<t>这个T为目的端的。typeid只对有virtual的虚类才有作用。也就是 polymorphic class type。http://www.cplusplus.com/reference/std/typeinfo/type_info/

5,vector 中的=就是copy。

6, 在C++的.h引用中,用#ifndef classFlag; #define classFlag #endif的方法,这个防止类重复定义。

7,一个类的私有函数其实就是一个类的private,是针对于类而言的,并不是针对于对象而言的。例如,拷贝构造函数中就可以在当前的构造函数中,调用另一个同一个类对象的私有成员变量。例如:

A(const A& a)

{

    this.num = a.num; //num是A类的私有成员

}

8,函数中char * a = "helloworld" 这个字符串是放在堆里面的。char a[] = "helloworld"是放在栈里面的。

9,explict 是用来避免隐式转换的。很多时候构造函数肯能会有隐式转换功能。例如:

A(int a);

A a(0); a = 5; 其实就是 A temp(5); a = temp; ~temp();

如果不想隐式转换,就必须用explicit。上面为explicit A(int a)就可以了。

 http://wenku.baidu.com/view/2d94f7264b35eefdc8d3334d.html

10,extern 的作用:他可以用于修饰变量和方法,它的主要作用是防止在一个.h文件中定义的一个对象,而在另一个文件中需要用extern连接。如果没有extern这个时候编译会出错误。因为他们都是先编译之后连接,如果编译之后再连接,就会出现同名的错误。

例如:a.h: int a; b.h extern int a 这个时可以的,方法也是,但是如果要是没有extern 连接的时候就会冲突

extern 'C' 这个主要作用就是为了让C++引用C中的方法的变量,因为C++ 有的时候编译的C是不一样的。例如,C++有函数重载的概念,而C总是没有的。所以int find(int a,int b)在C++ 编译之后会是 _find_int_int(注意没有考虑返回值),而C中的只有_find。这个时候如果不用extern,就会出现找不到函数的现象。

所以,需要在引用.h文件时候。extern 'C'{#include 'ac.h'},或者单独定义函数。

10,函数指针int* (*function)(int a, int b).

11, int const* p 和const int* p是一样的都是指向一个指向一个const int的指针,而int * const p才是指针不会变化的那种。 const int* const p呢 ?

12,UTF-8 3bytes UTF-16 2bytes。

13,__thiscall __cdecl这两个主要是标明当前这两个方法的主要类型,thiscall是类的成员函数,他在应用函数指针会出现问题,因为thiscall的函数基本都是通过类之后找函数表实现的,它的内部机制和普通的函数指针有所不同。而cdecl是回调函数,这个有一点好处就是函数指针可以直接引用。一般外围函数,和类的静态函数是cdecl的。这里需要注意如果你需要应用thiscall,就需要用到mem_fun和mem_fun_ref这两个STL类,他们的主要作用就是转化的。详细请看http://apps.hi.baidu.com/share/detail/4994454

14,C++存储区中分为堆,栈,静态存储区。一般常量是放在静态存储区里面的。

15,动态链接库是在进程启动的时候加载的。

16,只有指针才能动态绑定,对象是不行的。

0 0
原创粉丝点击