您的位置:首页 > 编程语言 > C语言/C++

C++基础知识总结

2016-01-04 22:07 537 查看
在C语言中,全局变量必须声明在所有的函数之前,局部变量必须声明在所有可执行语句之前; C++允许在代码块的任何位置对局部变量进行声明

常量定义方面,C语言 #define 可能因计算的优先级出现问题,C++

const:不允许在程序的任何位置改变const修饰符声明的常量,常量的名称一般用大写字母

C 语言不允许函数重载的概念,对于不同的数据类型需要给出不同的函数

在C语言中使用malloc()函数分配动态内存空间,使用free()函数释放动态内存空间;(需要包含malloc.h 或 stdlib.h)(malloc函数分配的空间无法得知存放的数据类型,返回的是void型指针,还应该将其返回类型强制转换)

C++中使用new delete (可以自动计算所需要分配的内存大小,并能返回正确的指针类型,若没有足够内存,将返回空指针)

C++ 动态特性:多态性,动态联编,虚函数

虚函数 —— 被virtual关键字修饰的成员函数,用于实现多态(多态的关键之处就在于使用指向基类的指针或引用来操作子类对象)

class A {
public:
virtual void print(){
cout<<"This is A"<<endl
};
};
class B:public A    {
public:
void print(){
cout<<"This is B"<<endl;
}

};

int main(){
A aa;
B bb;
A* s1=&aa;
A* s2=&bb;
s1->print();
s2->print();
}


多态性实现方式:强制多态(类型强制转换),重载多态(函数及运算符重载),类型参数化多态(模板),以及包含多态(类继承已经虚函数)

静态联编—— 联编工作出现在编译链接阶段,联编过程在程序开始运行之前完成

动态联编 —— 在编译阶段并不知道要调用哪个函数,只有在程序执行时才能确定,联编工作在程序运行时进行

C++ 类体中不允许对所定义的数据成员进行初始化在类的成员函数中调用非成员函数,在非成员函数前面必须加上 ::

构造函数必须是共有的仅当没有自定义构造函数时编译器才会自动创建

浅拷贝就是对默认拷贝构造函数所实现的的数据成员逐一赋值,如果类中含有指针类型数据,将会产生错误,为了解决问题,需要显示定义拷贝构造函数,使其不但可以复制数据成员,而且可以为对象分配内存空间,这就是深拷贝。如果在类定义中没有声明,C++编译器会自动在类中加入四个函数:构造函数,析构函数,拷贝构造函数,拷贝赋值函数。

析构函数只能有一个析构函数是成员函数,析构函数可以手动调用也可以被系统调用当一个对象是使用new运算符动态创建的,那么在使用delete运算符将其释放时,会自动调用析构函数

静态成员变量不是实例对象的一部分,而是所有对象所共有的,因此必须在类的内部声明,在类的外部定义

友元提供了不同类与函数之间数据共享的能力 ——普通的成员函数只能访问其所在类内部的其他成员,而被声明为友元的函数则卡宴访问相关的所有类内部的成员友元的关系不是双向的友元关系不能被继承友元关系不能被传递

如果遇到派生类成员和基类成员的名称冲突的情况,程序会采用派生类成员执行相应的操作。如果需要使用基类中的同名成员,则必须在程序中使用全局分辨符“::

虚基类 —— 派生类在继承基类时加入“virtual”关键字,应用中将只存在一个基类的拷贝;

如果同一继承层次中既有虚基类又有非虚基类,那么程序执行时会先调用虚基类构造函数,然后调用非虚基类构造函数,最后调用派生类构造函数

如果类中有成员类,成员类的构造函数被优先调用

类的默认访问方式是private

protected —— 相对于派生对象是公有的成员,相对于没有派生关系的对象是私有的成员

从C++本身来讲,struct 和 class 除了默认的成员访问权限不同之外,二者之间没有任何的区别

struct 中默认的成员访问权限是public,设计继承关系时,如果没有显式指定派生类与父类的继承方式

class的继承方式默认是private,而struct的继承方式默认是public

通过扩充派生类的构造函数,来实现向基类构造函数传递参数的操作

Derived(int x,int y):Base(y)

把函数体同函数调用相关联成为捆绑(早期捆绑——由编译器和连接器在程序运行之前的编译阶段完成的;晚期捆绑——程序运行阶段动态确定调用的函数体)

晚期捆绑只对虚函数起作用,而且只发生在使用一个包含虚函数的基类地址时 —— 晚期捆绑是实现多态的基础

如果一个函数在基类中被声明为 virtual ,那么在所有的派生类中它都是virtual

,派生类中的重载的虚函数的返回类型必须与基类中的原型相同

虚函数不要重复定义(在继承类中)

纯虚函数 —— 被标明为不具体实现的虚成员函数,其允许函数先声明一个操作名称而不给出操作内容,当派生类继承它以后在根据具体的需求给出适当的定义

virtual void foo()=0;

实现一个公共的接口 —— 纯虚函数规定了继承该类的程序必须实现纯虚函数,否则程序就不能实例化

含有纯虚函数的类成为抽象类 —— 不能被实例化

如果派生类中没有将纯虚函数实现,则这个派生类仍然是一个抽象类

构造函数不能使virtual —— 没有意义;

析构函数可以是virtual的 —— 当使用delete操作符删除对象时,隐含对析构函数的一次调用,若是虚函数,采用动态捆绑

sizeof 返回一个变量或数据类型在内存中所占用的字节数

地址是内存单元的编号,指针则用于存放内存地址

指针的运算

取地址运算:&,返回指定变量在内存中的存储地址

* ,取内容运算,返回指针所指向的变量的内容

函数指针 —— 函数类型 (*指针变量名)(参数);

函数指针指向存储区中某个函数的入口地址,因此可以通过函数指针调用相应的函数,也可以充当函数的参数(传递形参的应是某个函数的入口地址 )

#include <stdio.h>
#include <IOSTREAM.H>
int Get(int (*)(int),int);
int gett(int);

void main(){
int num;
num=100;
cout<<Get(gett,num)<<endl;
}

int Get(int (*p)(int),int){
return (*p)(int);
}

int gett(int i){
return i;
}


指针函数 —— 返回类型为指针的函数

指针与const

const 位于指针声明符之前 —— 常量指针 —— 指针所指向的对象是一个常量

const char * ss= “world”;


程序中不能试图对ss所指向的存储单元中的内容做出修改

const 修饰符位于指针生命符之后 —— 指针常量 —— 指针所标识的地址不可改变

枚举类型 —— 下标自0开始 enum 枚举类型名 { 常数表 }

C++ 的异常处理机制实际上是一种运行时通知机制

delete p;

只是删除指针p指向内存区,并不是删除指针p,所以p还是可以用的。删除空指针所指向内存是可以的。

为了避免内存泄露,在删除一个指针后应该将其其值赋为0。

常量指针是指针指向的内存区域地址不能改变,但是该内存地址里保存的值是可以改变的,比如int a; int * const p = &a; a的值可变

指向常量的指针表示指针指向的对象是不能被修改的,但是该指针可以被修改,即该指针可以指向另一块目标内存地址。比如

const int a = 0; const int *p = &a;


如果A是一个类,也可以为const A* p = new A;

可以理解成只读指针

而指向常量的常指针表示指针本身不能被修改,其指向的内存地址内容也不能被修改。比如const int a = 0; const int * const p = &a;

既然引用实现了指针的功能,而且使用起来更加方便,为什么还要指针呢?

这是因为指针可以为空,但是引用不能为空,指针可以被赋值,但是引用只可以被初始化,不可以被赋为另一个对象的别名。

如果你想使用一个变量来记录不同对象的地址,那么就必须使用指针,另外指针也可以是多重的。指针可以指向堆中空间,引用不能指向堆中空间。但指针和引用可以一同使用,另外要注意引用的生命周期。

对于引用而言,如果引用是一个临时变量,那么这个临时变量的生存周期不会小于这个引用的生存期。指针不具备这个特性。

为了避免内存泄露,我们不能按值的方式返回一个堆中对象,而必须按地址或者别名的方式返回一个别名或者内存地址,这样就不会调用复制构造函数来创建一个该对象的副本了,而是直接将该对象的别名或者地址返回。

为了避免指针混淆,我们必须对堆中的内存在哪个函数中创建,就在哪个函数中释放。

在一条语句中自加运算符的执行顺序为从右向左,且不同的编译器入栈的顺序不同。

比如说VC6.0中其入栈是要求该语句的表达式执行完后

a=1;cout<<a++<<++a;


则分别输出的是2,2;

++的结合性为右结合,所以++++i合法,而i++++不合法,可以改为(i++)++;

如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,那么在派生类中访问共同基类中的成员函数时会产生二义性,解决方法是需要指定类的作用域,或者将共同的基类设置为虚基类,因为虚基类不会产生二义性。

一个虚函数被说明为虚函数,在派生类中覆盖了该函数,那么该函数也是个虚函数,不过你也可以在它前面添加关键字virtual,这样更容易理解。

继承所体现出的不同子类相同函数有不同的表现,但是这个并不能体现类的多态性,因为类的多态性要求可以用基类指针来操作子类。

如果a表示的是数组指针,delete[] a,表示删除堆中的指针数组a,而delete a,表示删除堆中的指针数组第一个指针。

由于malloc和free函数产生于C语言时代,因此不可用在c++的对象中,因为对象的产生要调用构造函数。

函数名是指向函数的第一条指令的常量指针,这与数组名是指向数组中第一个元素的常量指针一样。

函数指针应该将函数名和前面的指针给括起来。

使用函数指针可以减小一些重复的代码,因为函数指针名可以看作是函数名的代号,我们可以通过它来直接调用,函数指针经常会在条件或者判断语句里出现,以便于用户选择调用不同名字但又返回值类型和参数类型完全相同的函数。函数指针可以作为函数的参数传入。

char字符串的比较只能用循环的方式进行(或者使用库函数strcmp函数),而string的比较可以直接用等号。

不可以直接对char型字符串数组进行赋值操作,而只能使用strcpy函数,或者对数组每个元素一个个的赋值。而string类的字符串可以直接用等号进行赋值。另外,string类中还有一个专门的赋值函数assign,这个函数可指定赋值字符串起点和长度。

查看char型字符串的长度可以用strlen函数。string中用size成员函数实现该功能。在char中,strncat可以实现部分字符串的合并。在string中是append函数。同理,char中用strncpy来实现字符串的替换,在string中使用replace来实现该功能,且replace的重载函数中可以兼容char型字符串数组。

char型字符串的拷贝用memmove, string中使用copy成员函数。

string中用insert来插入,其string类是从下标为1开始数的。erase完成字符串的删除。

char型字符串的查找使用函数strchr。而string类中使用find函数实现。该函数有很多变形的函数,比如find_first_not_of函数,表示找到第一个不相同的字符。同理还有find_first_of,find_last_of等函数。反向查找使用rfind()函数,但是它的返回值位置还是从头开始的,并不是从末尾开始的。

string中用compare实现比较,它的c_str()返回一个指向char型的const指针。

包含对象是将另一个类的对象作为该类的成员,而嵌套类是在该类中定义了一种新类型,这个类型只能在该类中使用。由于嵌套类作为一种自定义的数据类型被封装在另一个类中,因此可避免与其它类的名称冲突。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: