C我的笔记讲解.docx
- 文档编号:29090415
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:24
- 大小:1.20MB
C我的笔记讲解.docx
《C我的笔记讲解.docx》由会员分享,可在线阅读,更多相关《C我的笔记讲解.docx(24页珍藏版)》请在冰豆网上搜索。
C我的笔记讲解
1,内联函数,关键字inline,内联函数的实现有两种方法,一种是把函数的申明和定义写在一起,另一种方法是在类里用关键字inline声明函数,然后在类外定义内联函数,内联函数和普通函数的区别是内联函数只是把函数体复制到调用该函数的地方,而普通函数则是在调用函数时跳转到该函数执行,内联函数的好处就是减少运行时间,但是会增加程序体积,所以要求函数体积尽量小且调用次数多才划算。
2,域属符号,“:
:
”voidA:
:
print();//A为类,
3,函数声明和定义的区别,声明指示告诉编译器有这个符号,不会占用内存,定义则相当于函数的实现,在内存中是要占位置的。
4,头文件和源文件,可以把类的声明和定义放在一个头文件中而把执行放在c++文件中,
5,const函数,对于不想改变对象的成员变量的成员函数,在函数体前面可以用const修饰,这样做可以方便用于查错,就是对于这个函数本来不打算修改私有数据的值的时候就可以用const修饰。
6,构造函数,构造函数就是函数名和类名一样的函数,构造函数都是内联函数,在创建对象的时候,可以直接调用构造函数来创建对象,例子rectanglea(3,4);就是在创建对象的时候对其进行初始化。
构造函数是没有返回值的。
一个类中可以有多个构造函数,区别就是参数的不同,参数个数不同或者参数的类型不同。
7,默认构造函数,该函数没有参数,而且不执行任何代码,没有任何功能A(){},只是用于创建一个对象。
当我们创建一个构造函数时候就可以覆盖默认构造函数。
每个对象在创建时候都要调用构造函数来自己初始化,假如你没有提供一个构造函数,那么编译器就会自动建立一个默认构造函数,假如你创建了一个构造函数,不管你创建的是默认构造函数还是带参的构造函数,编译器都不会再为你提供任何默认构造函数,假如你还需要一个不带参的构造函数,你就必须自己写,否则当你在调用没有参数的构造函数的时候就会出错。
8,析构函数,销毁一个对象,释放对象的内存,析构函数没有参数和返回值,而且只能有一个析构函数,
9,对象数组,Aa[2],
10,this指针,this指针保存的是该对象的地址,默认情况下,this指针式省略不写的,就是说在成员函数中调用数据的时候都是省略了this指针的,
11,常量指针,int*constp=&a;常量指针必须初始化。
常量指针是可以改变指针指向的内容,但是不能改变指针的值,这里需要注意的是指针的相关知识,就是指针的类型和指针指向的内容的类型以及指针的值和指针所指向的内容的值。
12,堆中的对象,堆中的指针式通过new来创建的,所以堆中的对象是通过指针来进行访问的,
13,引用,引用就是别名,相当于大名和小名,intnum;int&mun=num;‘&‘,这是引用运算符,不是取值运算符,取值运算符可以用在任何时候,引用运算符则不能,还有一个方法区别’&‘是取值运算符还是引用运算符的方法就是看其是左值还是右值。
引用一定要记得初始化。
还有引用是常量,只能初始化不能赋值。
int&mun;mun=num;是错的,这是赋值而没有初始化。
引用的应用主要还可以用在函数传参,在函数定义的时候,若是参数是‘&’,则表示的是这个参数是别名参数,就就可以想用指针指针一样进行相关的操作,而不用那么的麻烦。
这才是引用最好的作用吧,
14,引用的地址,引用的地址和被引用的变量的地址是一样的,无论改变哪一个都是对变量进行修改。
引用一旦使用就相当于是指针常量,只会指向引用的变量,后续的操作都相当于是赋值操作,也就是改变引用的变量的值,就和常量指针的概念一致了。
15,引用对象,HumanMike;Human&rMike;引用不能使用于类,其实很简单,就是类是没有实际的内存地址的,就相当于int类型一样,
16,空引用,引用不用像指针那样对内存进行相应的操作。
17,按值传递,其实就是函数传参是传递的是数值而不是地址。
实质是传参的过程中,编译器为为传递的参数创建副本,就是说创建了新的数据。
18,按址传递,就是函数传参的时候传递的指针。
19,按别名传递,就是函数在传参的时候的简便方式,简单的说就是,在函数定义的时候,参数是‘&a’,在函数传参的时候,这个符号是别名符号而不是取地址符号。
20,利用指针返回多值,当传递的实参改变的时候实质上就相当于返回了函数的值,所以想要返回多个值就可以对参数进行改变,这里就可以用传递指针和传递引用。
这也是引用传参的用处。
当然还有其他方法。
但是这种方法可以就是进行多种运算,例如一个函数需要运算一个圆形的面积和周长等。
就可以用一个函数来实现了。
21,利用引用来返回多值,这种方法和用指针来返回多值是一样的,而且这种方法更简单。
还是有一点需要注意的就是当函数定义的时候,当参数是‘&’形式的时候,这是别名的符号,这点切记,而且在函数定义的时候是不会出现取地址符号的,所以当函数定义的时候有‘&’符号的时候就一定传递的别名参数。
22,按值传递对象,我们知道传递值的时候,是要对该值进行拷贝的(副本),这样的话当值很大(比如对象很大),这种开销就很大,对象就是一个变量,这点是可以理解的,还有就是对象在拷贝的时候,该对象的构造函数和析构函数都会被执行,这样系统的开销就很大。
返回对象的时候,相应的开销也是一样的。
这里还有一个复制构造函数的概念,
23,按地址传递对象,Aa;func(&a);只有在返回一个对象的地址的时候才不会进行复制,但是这种方法可以对该对象进行修改了,这就破坏了数据的安全性了。
24,使用const指针来传递对象,constA*constfunc(constA *constone){},这个函数的定义可以很好的看出函数返回值的常量的定义。
对于这个函数,用于接收这个函数的返回值的指针也是需要一个常量指针。
常量指针指示说明了不能通过这个指针来改变指向对象的值,但是原始对象是可以通过原始对象对其进行修改。
25,按别名来传递对象,A&func(A&one){};A&b=func(a);,
26,指针的别名,
27,引用的常用错误,当引用的对象不存在的时候,
28,析构函数和delete运算符,记得当在函数中调用了new函数的时候一定要调用delete,delete运算符会自动调用析构函数来销毁相应的内存空间。
29,默认析构函数,~A(){},
30,调用构造函数进行类型转换,我们可以把数字当做对象赋给另一个对象(z=1000,隐式转换),等价于a=A(1000),明示转换,强制类型转换,把1000转换为int型,,这样在对该复制表达是进行计算式,首先要对数字进行类型转换,同时判断该类的构造函数的参数是否与数字的类型匹配,假如匹配则调用构造函数创建一个临时对象,最后调用析构函数删除临时对象。
取消类型转换的函数,在前面加上explicit关键字就可以让其不能强制转换
31,函数重载,函数名相同参数不同。
参数不用是指函数个数不同和参数的类型不同,
32,成员函数重载,
33,函数的缺省参数(默认参数函数),voidfunc(intn=0,intm=0),也可以写为voidfunx(int=0,int=0);当在调用函数的时候若没有传递值(func();),则用默认的值,若传递了参数则用传递的值。
主要就是用在类中的设置函数,这种方式和函数的重载有一定相似的地方。
34,重载函数和缺省参数函数的区别,重载函数使用方便,易于理解,默认参数的函数如果不加标注的话很容易被忽略,而且容易被有参数的同名函数覆盖;具有默认参数的函数重载的是参数的数值,而重载函数重载的是参数的类型。
35,构造函数的重载,
36,成员变量的初始化,在构造函数中初始化,还有一种就是在构造函数的函数头进行初始化:
例子,rectangle():
length(3),width(4){….},
37,rectangle(inti,intj):
length(i),width(j){….},这两种方法的区别就是如果成员变量被const修饰的话,则第一种会出错,实质上是第一种方式是对变量的赋值,二第二种方式则是对变量的初始化,所以如果有成员变量是常量(const)或者引用的话,必须用第二种方式。
当成员变量有父类对象时,可以直接调用父类的构造函数,实现方法就和对本类的成员变量初始化一样,rectangle():
father(23),length(3),width(4){….},
34,成员变量的初始化和构造函数的调用,当成员变量是对象的时候,这调用构造的顺序是按成员变量的顺序来的,而不是按照
如上图所示,析构函数则相反,
35,复制构造函数,A(){},A(constA&one){this->n=one.n},this指针可以省略,每一个类都有一个默认的复制构造函数。
上面的程序不是浅拷贝,代码应该是
上面程序的delete会出现问题,delete会调用析构函数,则会删除x的内存,则在main函数返回的时候,又会再次调用析构函数,但是这时候X指针所指的内存已经删除了,则程序就会崩溃。
这种方式就是浅拷贝,这种拷贝的话,若是成员变量中有指针的话,则很容易出现问题,下面则是另一种方式。
1,继承和派生,继承是指子类和父类相同的成员变量,派生是指子类从父类那继承过程中具有新的特性的过程就叫做派生。
继承的方式有单一继承和多重继承。
Class儿子:
public父亲
2,
3,单一继承,例子(实际上变量是不能是汉字的,下面只是一种范例)
class父亲
{
private:
int父亲身高,父亲体重:
public:
void设置父亲身高(int父亲的身高){父亲身高=父亲的身高;}
void设置父亲体重(int父亲的体重){父亲体重=父亲的体重;}
void输出父亲身高体重(){...}
};
class儿子:
public父亲
{
private:
int儿子肩宽,儿子臂长:
public:
void设置儿子肩宽(int儿子的肩宽){儿子肩宽=儿子的肩宽;}
void设置儿子臂长(int儿子的臂长){父亲臂长=父亲的臂长;}
void输出儿子肩宽臂长(){cout<<"肩宽="<<儿子肩宽<<...}
}
intmain()
{
儿子李明;
李明.设置父亲身高(180);
李明.设置父亲体重(80);
李明.设置儿子臂长(134);
李明.设置儿子肩宽(100);
李明.输出父亲身高体重();
李明.输出儿子臂长肩宽();
return0;
}
1,保护型成员,对于一般类来说是不能访问的,但是对于子类是可以访问的,这是protect关键会有的原因,就是为了给子类用的。
2,公有派生,class儿子:
public父亲
//公有派生的公有成员例程如下:
/*
#include
usingnamespacestd;
classfather
{
public:
voidroom(){cout<<"父亲的大房子我可以享受\n";}
};
classson:
publicfather
{
};
intmain()
{
sona;
a.room();
return0;
}
*/
//公有派生的保护权限例程如下:
/*
#include
usingnamespacestd;
classfather
{
protected:
voidroom(){cout<<"父亲的大房子我可以享受\n";}
};
classson:
publicfather
{
public:
voidenjoy(){room();}
};
intmain()
{
sona;
a.enjoy();
return0;
}
*/
//公有派生的私有成员例程如下:
/*
#include
usingnamespacestd;
classfather
{
private:
voidsecret(){cout<<"父亲的秘密\n";}
};
classson:
publicfather
{
public:
voidenjoy(){secret();}
};
intmain()
{
sona;
a.enjoy();
return0;
}
*/
//2.私有派生,基类的所有东西都是private类型,所以需要间接的方式访问
#include
usingnamespacestd;
classfather
{
public:
voidroom(){cout<<"父亲的大房子我可以享受\n";}
};
classson:
privatefather
{
public:
voidenjoy(){room();}
};
intmain()
{
sona;
a.enjoy();
return0;
}
1,多重继承,classson:
publicfather,publicmother,classson:
publicfather,privatemother
2,继承的构造和析构函数,构造函数的调用顺序是按照继承时给定的顺序,从左到右,西沟函数则是相反。
3,想基类构造函数传递参数,一种是直接在构造函数体重实现变量(继承致父类的变量和子类本身的变量,成员变量可以是基本的数据类型,也是可以是类创建的对象)的赋值,但这种方法有缺陷,会调用父类的构造函数,却没有进行有效的工作,增加系统开销;另一种就是调用父类的构造函数,在父类的构造函数中对父类的成员变量进行赋值,也许这就是构造函数有多个的用处吧,后一种方法也使代码的可读性大大增强。
4,多继承容易产生两义性,是指可能调用的函数不清楚是从哪个父类继承来的,解决的方法是用c.A:
:
hello(),加上域属关键字就可以了,作用域操所符。
5,继承中的重载,当我们在子类中定义一个与基类同名函数时,那么等于是告诉编译器,用子类的函数覆盖掉基类的同名函数,同时将他的重载函数隐藏起来。
6,指向对象的指针,const修饰的对象只能调用const函数。
father*p=newson;,一个子类的对象可以赋值给父类指针(多态性),这样就建立了子类和父类的联系,还有需要注意的是这个指针在调用函数的时候的问题,这个指针只能调用父类所占内存所在大小内存中的成员函数,这是由于指针的性质决定的,可以用内存的思想来考虑下。
7,虚函数,virtualvoidrun()const{cout<<”父亲可以跑万米\n”;},就是说在函数的前面加上virtual关键字。
father*p=newson;对于这种形式,因为在函数run()前面加virtual,表示该函数是有多种形态的,即该函数可能被多个对象所拥有,而且功能不一,换句换说多个对象在调用同一名字的函数时产生效果也不一样。
那么系统在执行有关键字virtue的函数时候就会自动判断是哪个对象调用了它,然后调用该对象的同名函数。
8,虚函数的用处,对于不同的拳击选手都会有beat功能,但是每个拳击选手的beat功能确是不同的,一个函数被声明为虚函数,则在派生类中覆盖了该函数,那么该函数也是个虚函数,当然你也可以加上virtue关键字,换句话说就是只要一个函数定义为虚函数,那么它派生后就只能是虚函数了。
下面是例子。
#include
usingnamespacestd;
classposer
{
public:
virtualvoidbeat()const{cout<<"一般选手一拳的力量为260磅\n";}
protected:
intage;
};
classAli:
publicposer
{
public:
voidbeat()const{cout<<"阿里一拳的力量为420磅\n";}
};
classLewis:
publicposer
{
public:
voidbeat()const{cout<<"刘易斯一拳的力量为480磅\n";}
};
classTyson:
publicposer
{
public:
voidbeat()const{cout<<"泰森一拳的力量为500磅\n";}
};
classholy:
publicposer
{
public:
voidbeat()const{cout<<"霍利菲尔德一拳的力量为350磅\n";}
};
voidmain()
{
poser*a[5];
poser*p;
intchoice,i;
for(i=0;i<5;i++)
{
cout<<"
(1)阿里
(2)刘易斯(3)泰森(4)霍利菲尔德:
";
cin>>choice;
switch(choice)
{
case1:
p=newAli;//选择1时,新建Ali对象,并用指针p来指向它
break;//跳出switch语句
case2:
p=newLewis;
break;
case3:
p=newTyson;//选择3时,新建Tyson对象,并用指针p来指向它
break;
case4:
p=newholy;//选择4时,新建holy对象,并用指针p来指向它
break;
default:
p=newposer;//默认时,也就是选其他数字,新建poser对象,并用
//指针p来指向它
break;
}
a[i]=p;//将p指针赋给数组元素,元素中保存的是对象地址,
//关于数组的概念后面还要详细讲解。
a[i]->beat();//通过数组中保存的指针来访问函数,由于是间接访问,所以要
//加指向成员运算符->
}//for循环结束
}
这个代码的思想可以借鉴一下(循环部分),
9,继承是否能实现多态性,在不使用virtue之前,c++对重载函数使用静态联编,而使用了virtue以后,C++则对该函数进行动态联编,
10,系统是如何调用虚函数的,
11,虚构造函数和虚析构函数
12,纯虚函数和抽象类,例子:
virtualvoidsleep()=0;
13,静态成员变量,静态成员变量是属于类而不属于某一个对象,换句话说就是静态成员变量需要分配内存。
静态成员变量和构造函数和析构函数一起用可以标记这个类创建的对象的个数。
静态成员在没有对象之前就存在。
1,静态成员,静态成员的特征是不管这个类创建了多少个对象,而其静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。
静态成员数据不能在类中进行初始化,因为在类中不能为其分配空间,静态成员实在编译时创建并初始化。
私有静态数据成员不能被类外函数访问,也不能用对象进行访问。
用静态成员的一个主要原因就是不必使用全局变量。
静态数据成员的主要用途就是定义类中的各个对象所共用的数据,如统计总数,平均数等。
2,函数指针,
4,成员函数指针,
11,包含,一个类中包含另一个类的对象,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 我的笔记讲解 笔记 讲解