静态函数的可以对象不用实例化,直接类名.函数名调用
拷贝构造函数:创建一个CExample类包含两个函数,一个构造函数,一个拷贝构造函数,定义一个CExample对象,
CExample B = A; // CExample B(A); 是一样的,那么会自动调用CExample(const CExample& C) 就是我们自定义的拷贝
//构造函数,它必须的一个参数是本类型的一个引用变量。
- //全局函数
- CExample g_Fun()
- {
- CExample temp(0);
- return temp;
- }
当g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
(注:返回对象将调用复制构造函数,而返回引用不会,效率更高)
由于const函数可以保证不修改类里面的成员变量,那么变量加上mutable可以抵消
常量(const)和引用在一个类里面定义了必须初始化,如果const一个对象,那么不可以调用非const的成员函数
指针数组的应用:创建一个指针数组,每个指针指向一个MainWindow对象,for遍历每个元素,可以p[i]对每个对象进行操作
struct foo { string name ; int id ; foo(string s, int i):name(s), id(i){} ; // 初始化列表 };这里是初始化列表的用法:foo构造函数传进来后,s赋给name,i赋给id
new和delete会自动调用构造析构函数,而malloc和free只会分配内存,不会调用
多继承:
当一个类继承了另外两个类时,那么写它的构造函数也应当这样写
这样调用zajiao的构造函数时候也分别调用了继承的那两个类的构造函数,调用函数方法的时候这样调用区分3个类
私有继承是把父类所有变量都变成私有,保护继承是把父类公有变量变成保护变量
假设一个类fushu,代码 fushu fu=10;会自动进行隐式转换也即fushu fu=fushu(10);(该代码和fushu fu=(fushu)10等同)将10作为参数跳转到fushu的构造函数,然而如果我们不想让他进行隐式转换需要在构造函数前面加上explicit,必须前面加上fushu这样的显示转换才可以
这里fushu fu=10可以转化为fushu fu(10);那么我们zhengshu zheng; fushu fu=zheng这样是不行的两个对象类型不匹配,如何让它成立呢,因为fushu fu=zheng等价为fushu fu(zheng);那我我们在fushu 的构造函数中传参传zhengshu对象就可以了
父类的指针可以用个强转成子类指针访问子类的同名函数
抽象类不可以实例化,把所有接口都实现了才可以实例化,一个或多个虚函数是个指向虚函数表的指针,占4个字节
类模板:
初始化两个类模板,当传入t111时,赋值给t11。传入t222赋值给t22实际调用的时候传入实际类的类型即可
这里final函数必须是虚函数,作用是该函数无法重写
override只存在于子类当中,且函数是父类含有的且是虚函数,用于警示覆写父类的同名函数
一般类里定义一个static变量可以用来记录创建的对象数目
在构造函数中使用new来分配内存时,必须在相应的析构函数汇总使用delete来释放内存,如果使用new[]来分配内存,使用deletel[]来释放
一个对象里面不要这样复制字符串(指针):
sailor.str=sport.str //这样是字符串的指针复制,这样会析构两次,出错,
string的浅拷贝是让两个不同的指针指向同一块空间,而这在析构的时候会出现将一块空间释放两次,程序会崩溃,因此我们才需要进行深拷贝,即第二个指针开辟和第一个指针一样大小空间,然后将内容复制过去。
解决办法是深拷贝,同理对象赋值里面包含指针你就要小心了,要用深拷贝
StringBad::StringBad(const StringBad & st)
{
len=st.len;
str=new char[len+1];
std::strcpy(str,st.str);
}
这里this指什么呢,我觉得调用的是String对象里面的方法,所以指String对象
String & String ::operator=(const String & st)
{
if(this==&st)
return *this;
}
静态联编:由于重载,编译器必须查看函数参数以及函数名才能确定是哪个参数,这种在编译过程完成的联编叫静态联编
动态联编:编译器必须生成能够在程序运行时选择正确的虚方法的代码
如果定义的类将被用作基类,那么应将这些要在子类中重新定义的类声明为虚的,虚函数为了重载和多态,在基类中有定义,所以子类中可以重写也可以不写,纯虚函数(在虚函数后面加上=0为纯虚)在基类中不定义,必须在子类中加以实现
创建子类对象时,先调用基类的构造方法,然后调用子类的构造方法,删除对象时,先调用子类的析构,在调用父类
抽象模板类:
由于抽象类不能实例化,那么只能用一个指针来进行初始化
使用c++在一个字符串提取子字符串,先创建一个结构体,保存所以可能类型,然后扫描完可以输出所有的子字符串
这里每个字符串中间有个空格所以我们可以提取子字符串,如果每个字符串直接是#我们可以将#换成空格然后。。。
内存映射:对于几TB的海量存储,不能用一些ReadFile,WriteFile这些api来读写文件,将文件从磁盘加载到内存,可以解决多个进程共享数据的问题
Lambda表达式:是一个匿名函数,即没有函数名的函数。,比如在c++中
如果在[]当中加this,说明要引用this
这里->指的返回类型为double
有空看看100条经典的c++笔试题目,
进程间通信的方式
1 管道技术
2 消息队列
3 信号
4 共享内存
5 socket
重载和重写的区别:
重载:允许存在多个同名函数但是参数不同
重写:子类重写父类的虚方法
c++中有一些运算符不允许被重载,比如. 比如#@$
多态:多态分为两类:静态多态性和动态多态性,以前学过的函数重载和运算符重载实现的多态性属于静态多态性,在
程序编译时系统就能决定调用哪个函数,因此静态多态性又称为编译时的多态性。静态多态性是通过函数的重载实现的。
动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。动态多态性是通过虚函数实现的。
虚函数表:一个类中所有虚函数地址构成的表叫虚函数表,派生类的虚函数地址会覆盖基类的地址,多重继承时,子类没有发生覆盖的函数被放到第一个父类的表中
静态成员函数不能为虚函数,内联函数也不能为虚函数,构造函数不能为虚函数,析构函数可以为虚函数
如果父类的析构函数不是虚函数,那么最后只调用父类的析构,不会调用子类的析构,造成内存泄漏,所以,一定要在父类析构设成虚的,才会父类子类都调用析构函数
使用string类,不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个对象
char char1[20];
char char2[20]="sdfsd";
char1=char2; //不允许
string str1;
string str2="sdfsdf";
str1=str2; //可以这样做
str str3;
str3=str1+str2; // 将两个str2放到str1后面
共用体union的长度为最大成员的长度。用于节省内存
面向对象与传统的过程编程区别在于OOp强调在运行阶段而不是编译阶段进行决策
long * fellow;
*fellow=233; //指针指向哪里呢,因此指针必须要初始化为一个确定合适的地址
c语言的初始化指针:
int higgens;
int *pt=&higgens;
c++指针初始化:
int *pn=new int; //如果int *pt; pt=0xB800000;这样类型不对pt=(int *)0xB80000才对
编译时给数组分配内存叫做静态联编,
int tacos[10];
new在运行时需要数组就创建它并创建长度,不需要就不创建,叫动态联编
int size;
cin>>size;
int *pz=new int[size];
delete[] pz;
问:什么时候用.什么时候用->
答:如果是结构名用.如果是指针指向结构用-> 比如(*ps).name这里*ps指向结构实体,ps->name这里ps是某个结构体指针
new char数组是[]里面都是strlen[a]+1这里+1是‘\0’如果new 出来的数组没有赋值那么声明的空间大小中每个元素都是'\0'
对于一个数组ar如果ar+4==&ar[4]表示的是第五个元素的地址
const float g_earth=9.8;
const float *pe=&g_earth; // 这个是正确的,既不能修改变量也不能修改指针
const float g_earth=9.8;
float *pm=&g_earth; //这是不对的
这样可以用pm修改g_earth,因此c++禁止将const地址赋给非const指针
double pam(int); 这是一个函数原型,函数名为pam,若求该函数的函数指针,意思是把函数变成指针的形式,double (*pf)(int)这里指针pf就是函数指针
const double *(*pa[3]) (const double *, int)
看这个要一层一层看:pa[3]看成double pa[3]明显是个包含3个元素的数组,*pa[3]看成double *pa[3]明显是个包含3个指针的数组,然后再看最外层,const double* (const double,int) 这是一个函数返回double的指针
最后这样回答:pa是一个包含三个指针的数组,每个指针指向这样的函数:const double*和int作为参数,返回值为const double*
对于double pa[3]这个数组,pa和&pa还是有区别的,pa指的是第一个数组元素的地址&pa[0]但是&pa是整个数组的地址,也即三个double的地址,比如pa+1为下一个元素地址,&pa+1为pa地址+3*8字节的地址
double *pd[3] 表示有3个元素为double指针的数组
double (*pd)[3] 表示pd是一个指针,指向3个元素为double的数组
函数指针:
int func(int x); /* 声明一个函数 */
int (*f) (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
或者使用下面的方法将函数地址赋给函数指针:
f = &func;
赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。
指针函数和函数指针的区别:
指针函数是指返回值是指针的函数,即本质是一个函数。
函数指针是指向函数的指针变量。
函数模板:
template<typename T> //关键字template和typename是必须这样写或者把typename改成class也行
void Swap(T &a,T &b){
}
在调用函数的时候Swap<double>(4,5); 在函数名后面加上尖括号跟上泛型类型
在多文件程序中,可以在一个文件中定义一个外部变量,使用该变量的其他文件必须使用关键字extern
double *pd=new double(99) // *pd初始化为99
Jill::fetch是取得Jill里面的变量fetch,而using Jill::fetch这里using是将对象Jill里的变量fetch放到局部空间中,因此不能再声明局部变量fetch了,如果取得全局变量fetch用 ::fetch来得到
using namespace作用是让名称空间中所有名称都可用,using namespace Jack;让Jack里面所有名称都可用
当运算符函数是成员函数,第一个操作数将是调用该函数的对象,定义运算符函数如果第一个操作数不是类对象必须使用友元函数:
Time operator*(double n) const; //这里重载&运算符
friend Time operator*(double m,const Time &t) {return t *m} //但是对象*整数可以如果整数*对象就无法执行。如果*前面不是类对象就必须用友元函数
深拷贝与浅拷贝:
StringBad headline("dfsdfsdfdsfd");
StringBad knot;
knot=headline; //两个对象复制,这里是浅拷贝,这样的结果是数据受损,对knot析构,删除了字符串“dfsdfsdfdsfd”,当对headline调用析构是,试图删除已经删除的字符串,导致结果不确定,程序异常终止
解决办法:
重载=号运算符让对象复制实现深拷贝
c++中拷贝构造函数和赋值运算符不同点:
1.拷贝构造函数只是在对象实例化时才被调用,也即在调用拷贝构造函数期间,对象处于一个未决状态(直到拷贝构造函数被成功调用);而赋值运算符则在一个现存的对象被赋予新值时被调用。
2.拷贝构造函数没有返回值;赋值运算符有返回值。
举例:
class T
{
private:
static int count;
public:
T() {
count++;
cout<<"create T "<<endl;
}
T(const T& t) //拷贝构造函数
{
count++;
cout<<"copy create T "<<endl;
}
T& operator=(const T& t) //赋值运算符
{
count++;
cout<<"assignment op "<<endl;
return *this;
}
};
int T::count = 0;
int main(int argc, char** argv) {
T t;
T t1 = t; //调用拷贝构造函数
T t2(t); //调用拷贝构造函数
t1 = t2; //调用赋值运算符
T t3 = t2 = t1; //先调用赋值运算符,在调用拷贝构造函数
return 0;
}
摘自http://blog.csdn.net/wjf201003050643/article/details/52745050
pc1=new (buffer) JustTesting; //意思是new一个JustTesting对象地址和buffer这个数组地址一样
c++中多态的定义:同一个方法在子类和父类的实现是不同的。有两种机制用于实现多态:1子类重新定义父类方法2虚方法
但是博客中定义的多态是这样的:
多态:父类型的引用可以指向子类型的对象。
比如 Parent p = new Child();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;
如果有,再去调用子类的该同名方法。
如果想要调用子类中有而父类中没有的方法,需要进行强制类型转换,如上面的例子中,将p转换为子类Child类型的引用
class Student{
private:
std::string name;
ArrayDb scores;
public:
Student() : name("Null Student") ,scores(){} //意思是声明Student的构造函数,初始化name和scores为Null Student和空
使用私有继承,基类的公有成员和保护成员都成为子类的私有成员
class Student : private std::string, private std::valarray<double>{ //私有继承,多继承 }
32位系统指针长度为4字节, 64位系统 指针长度为8字节