主要知识点
C++期末需要掌握的知识点,根据复习要点总结。
指针
一级、二级指针的定义和基本操作
一级指针:指向变量
二级指针:指向一级指针
int a = 10;
int *p;
p = &a; //一级指针
int **q;
q = &p; //二级指针
数组与指针之间的相互操作
int a[10];
int *p;
p = a;
p = &a[0]; //3、4两句等价
动态数组如何实现
一维动态数组
int main(){
int n;
cin >> n;
int* a = new int[n];
}
二维动态数组
int main(){
int m,n;
cin >> m; //行
cin >> n; //列
int** a= new int* [m]; //m行的每行的第一个首地址
for (int i = 0; i < m; i++){
a[i] = new int[n]; //每行中n个元素的地址
}
new 和 delete 操作
用new和delete运算符进行动态分配和撤销存储空间
(1)new
开辟一个存储空间,并返回地址
(2)delete
撤销空间
因为是运算符不是函数,执行效率高,通常结合使用。
注意:用new分配数组空间时不能指定初值。如果无法正常分配,返回一个空指针NULL。
new 类型(初值)
delete 指针变量
//或者
delete []指针变量(对数组)
指针用做函数形参
作用:将一个变量的地址传送给被调用函数的形参。
void swap(int *p,int *q){}
int main(){
int a = 1;
int b = 2;
int *temp1,*temp2;
temp1 = &a;
temp2 = &b;
swap(temp1,temp2); //注意,千万不要写成(*temp1,*temp2)
}
const指针
指定指针变量是一个常量,或者指定指针变量指向的对象是一个常量。
1、指向常量的指针变量
注意:只是限制了通过指针变量改变他指向的对象的值。
const 类型名 * 指针变量名;
int a = 12,b = 15;
const int *p = &a;
*p = 15; //试图更改,非法
//但是指针变量p的值(p的指向是可以改变的)
p = &b;
a = 15;
//以上两种都是合法的,改变了值
2、常指针
常指针变量,简称常指针。必须在定义时初始化,指定其指向。
指针变量的指向不能改变,但指针变量的指向变量的值可以改变。
类型名 *const 指针变量名;
char *const p1 = "China";
p1 = "Canada"; //试图改变p1指向,非法
*p1 = "Canada"; //合法
3、指向常量的常指针
1、2两种叠加,指针变量指向一个固定的对象,该对象的值不能改变(不能通过指针变量改变该对象的值)。
const 基本类型名 *const 指针变量名;
int a = 10;
int b = 20;
const int *const pt = &a;
pt = &b; //非法
*pt = 30; //非法
a = 30; //合法
//若要完全禁止a改变
const int a = 10;
利用函数实现指定的功能
全局变量、局部变量和静态变量的特点
每一个变量都有其有效作用范围,这就是变量的作用域。在作用域以外是不能访问这些变量的。
全局变量
在函数之外定义的变量是外部变量,称为全局变量。
全局变量的有效范围为从定义变量的位置开始到本源文件结束。
局部变量
在一个函数内部定义的变量是内部变量,它只在本函数范围内有效。
静态变量
static声明,分为静态局部变量和静态全局变量。
static int a = 5;
局部:希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时的值。
全局:希望某些外部变量只限于被本文件引用,而不能被其他文件引用,可以在定义外部变量时加一个static声明。
重载函数的定义和特点
用同一函数名定义多个函数,而这些函数的参数个数和参数类型可以不相同,这就是函数的重载。
重载函数的参数个数、参数类型或参数顺序三者中必须至少有一种不同。
缺省值形参函数的使用
(待补充)
面向对象程序设计
面向对象程序设计的特点
抽象、封装、继承、多态性(有时只选3个)
类和对象的概念
抽象的作用是表示同一类事物的本质。
类是对象的抽象,而对象则是类的特例,即类的具体表现形式。
类的声明和使用
class Circle{
private:
float radius;//半径
float area;//面积
public:
Circle(){
radius = 0;
area = 0;
}
Circle(float r){
radius = r;
area = radius*radius*3.14;
}
Circle(Circle &c){
radius = c.radius;
area = c.area;
}
void print(){
cout<<"半径:"<<radius<<endl;
cout<<"面积:"<<area<<endl;
}
};
int main(){
Circle c1(2);
Circle c2(c1);
Circle c3;
c1.print();
c2.print();
c3.print();
return 0;
}
对象的声明和使用
见上
成员函数的概念
与一般函数的区别:是属于一个类的成员,出现在类体中。注意访问权限。
类的构造函数和析构函数的定义,特点
构造函数
构造函数不需要用户来调用它,而是在建立对象时自动执行。
class Student{
public:
Student(){
}//无参构造函数
Student(int a=0){
}//带默认参数的构造函数
Student(int a,int b){
}//定义有一个参数的构造函数
Student(Student &stu){
}//拷贝构造函数
};
//注意,上述四种构造函数不是都可以同时存在的
应在构造函数声明时指定默认值,而不是在定义时。
一个类只能有一个默认构造函数,即可以不用参数调用的构造函数,只能有一个。
一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。
使用参数初始化表来实现对数据成员的初始化
Box::Box(int h,int w):height(h),width(w){}
//花括号中可以没有内容,但必须有花括号
析构函数
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作不能被重载。
一个类可以有多个构造函数,但只能有一个析构函数,还可以用来执行“用户希望在最后一次使用对象之后所执行的任何操作"。
class Student{
public:
~Student(){
cout<<"调用析构函数!"<<endl;
}
};
特殊情况:
常数据成员,只能通过构造函数的参数初始化列表对常数据成员进行初始化,其他任何函数都不能对常数据成员赋值。
如果将成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改它们。
this指针
指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址。
this指针是隐式使用的,它是作为参数被传递给成员函数的。
编程序者不必人为地在形参中增加this指针,也不必将对象a的地址传给this指针。
什么时候会调用类的构造函数,析构函数
一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用。
先构造的后析构,后构造的先析构
如何写构造函数与析构函数
参考定义、特点
拷贝(复制)构造函数的写法和用途
参考定义、特点
哪些情况下会调用拷贝构造函数
在用已有对象复制一个新对象时被调用:
1、程序中需要建立一个对象,并用另一个对象对它初始化。
2、当函数的参数为类对象时。
3、函数的返回值是类的对象。
//1
Student stu1(5);
Student stu2(&stu2);
//2
void fun(Student stu1){
}
//3
Student fun2(){
Student stu;
return stu;
}
全局对象,局部对象和静态局部对象调用构造函数和析构函数的特点
1、全局对象:程序一开始,其构造函数就先被执行(比程序进入点更早),程序即将结束前其析构函数将被执行。
2、局部对象:当对象诞生时,其构造函数被执行,当程序流程将离开该对象的声明周期时,其析构函数被执行。
3、对于静态(static)对象,当对象诞生时其构造函数被执行;当程序将结束时其析构函数才被执行,但比全局对象的析构函数早一步执行。
4、对于以new方式产生出来的局部对象,当对象诞生时其构造函数被执行,析构函数则在对象被delete时执行。
友元函数和友元类的特点与使用
见下文
运算符重载
运算符重载的特点与使用
运算符重载的规则
1)不允许用户自己定义新的运算符。
2)不能重载的运算符有5个:"." , “*” , “::” , “sizeof” , “?:”
3)重载运算符不能改变运算符运算对象的个数、不能改变优先级、不能改变结合性
4)不能有默认的参数
5)重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少有一个是类对象
6)用于类对象的运算符一般必须重载,但有两个例外,运算符"=","&"
“<<",">>",和类型转换运算符只能定义为友元函数重载
一般将单目运算符和复合运算符重载为成员函数
一般将双目运算符重载为友元函数
几种常用的运算符重载的写法
class Complex{
private:
double real;//实部
double imag;//虚部
public:
Complex(){
real = 0;
imag = 0;
}
Complex(double r,double i){
real = r;
imag = i;
}
friend Complex operator +(Complex &a,Complex &b);
friend istream &operator >>(istream &in,Complex &a);
friend ostream &operator <<(ostream &out,Complex &a);
void display(){
cout<<real<<"+"<<imag<<'i'<<endl;
}
};
Complex operator +(Complex &a,Complex &b){
Complex c;
c.real = a.real + b.real;
c.imag = a.imag + b.imag;
return c;
}
istream &operator >>(istream &in,Complex &a){
in>>a.real>>a.imag;
return in;
}
ostream &operator <<(ostream &out,Complex &a){
out<<a.real<<"+"<<a.imag<<'i'<<endl;
return out;
}
多态性与虚函数
虚函数的特点与使用
virtual
虚函数就是在基类声明函数时虚拟的,并不是实际存在的函数,然后再派生类中才正式定义此函数。
虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
虚函数、纯虚函数、抽象类
抽象类:含有纯虚函数的类,也叫抽象基类
//抽象类
calss Shape{
public:
virtual float area() const {return 0;} //虚函数
virtual void shapeName() const = 0; //纯虚函数
}
如何实现动态多态性
多态性:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。
静态多态性:通过重载函数实现。编译时的多态性。
动态多态性:通过虚函数实现的。运行时的多态性。
静态关联:在编译时即可确定其调用的虚函数属于哪一个类。例:函数重载
动态关联:在运行阶段把虚函数和类对象“绑定”在一起。
函数模板和类模板的使用和编写
//函数模板
template<typename T>
T max(T a,T b,T c){
if(b>a)a=b;
if(c>a)a=c;
return a;
}
int main(){
int i1=10,i2=15,i3=5;
max(i1,i2,i3);
}
//类模板
template<class numtype>
class Compare{
private:
numtype x,y;
public:
Compare(numtype a,numtype b){
}
numtype max(){
return (x>y)?x:y;
}
};
int main(){
Compare<int> com(3,5);
}
类模板如何实例化,如何创建对象
见上条
函数模板和模板函数、类模板和模板类的区别
函数模板、类模板:重点是模板
//函数模板、类模板
template<typename T>
template<class numtype>
模板函数、模板类:重点是函数、类
max(i1,i2,i3); //模板函数
Compare<int> com(3,5); //模板类
继承与派生
继承的基本概念、特点
一个新类从已有的类那里获得其已有的特性,称为类的继承。
派生类是基类的具体化,而基类则是派生类的抽象。
继承后子类和父类构造函数和析构函数被调用的规律
1、调用基类构造函数
2、调用子对象构造函数
2、再执行派生类构造函数本身
析构函数则相反。
多继承的概念
一个派生类有两个或多个基类的称为多重继承。
继承方式包括:public,private,protected(默认private)
class Student:public People{
public:
Student(int n,int a):People(n){
age = a; //对新增数据成员进行初始化
}
};
public:
基类的public和protected在派生类中保持原有访问属性,其private仍为基类私有。
private:
基类的public和protected在派生类中成了私有成员,其private仍为基类私有。
protected:
基类的public和protected在派生类中成了保护成员,其private仍为基类私有。
protected的意思是,不能被外界引用,但可以被派生类的成员引用。
多重继承的二义性问题如何解决
可以通过直接派生类名来指出要访问的是哪一个派生类中的基类成员。
c1.A::display();
多继承中的虚基类的特点与使用
虚基类使得在继承间接共同基类时只保留一份成员。
注意:虚基类不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。
class A{};
class B:virtual public A{};
class C:virtual public A{};
class D:public B,public C{};
隐式类类型转换的方式
隐式类型转换
int i = 6;
i = 7.5+i;
//先将i从6转为6.0,相加等于13.5,赋值给i时再转换为13
显式类型转换
类型名(数据)
文件读写流的操作,如何实现两个文件之间的复制
#include<fstream>
#include<iostream>
using namespace std;
int main(){
char temp[20];
fstream in,out;
in.open("file1.txt",ios::in);
out.open("file2.txt",ios::out);
while(!in.eof()){
in.getline(temp,20);
cout<<temp<<endl;
out<<temp<<endl;
}
in.close();
out.close();
return 0;
}