学习要求
1:C++基础
要求:
1.进一步了解和熟悉VC++6.0开发环境,学会在VC++6.0环境下调试程序;
2.熟悉C++中简单的标准输入输出函数的实用;
3.理解const修饰符的作用,并学会应用const修饰符;
4.理解内置(内联)函数的优缺点并学会使用内置函数;
5.理解和使用函数重载以及带默认参数的函数;
6.使用new和delete进行动态内存管理;
7.理解和使用引用。
解答:
1,2略
3.const限定符
(1)const的初始化
1.定义的时候直接初始化
2.类中使用初始化列表进行初始化
(2)const的位置
1.数据类型前
#include
using namespace std;
int main()
{
int a = 1;
const int b = a;
//b = 2; //错误:b不能修改
return 0;
}
const限定后对指针的要求:
#include
using namespace std;
int main()
{
int a = 1;
const int b = a;
const int c = 2;
int *p1 = &a;
const int *p2 = &a;
p1 = &a;
//p1 = &c; //错误: 不能将const int *赋值给int *
p2 = &c;
cout<<*p1<
2.指针const
#include
#include
using namespace std;
int main()
{
int a = 1;
const int b = a;
const int c = 2;
int *const p1 = &a;
const int *p2 = &a;
const int *const p3 = &a;
//p1 = &c; //指向不能改变
*p1 = c;
p2 = &c;
//*p2 = c; //值不能改变
//p3 = &c; //指向不能改变
//*p3 = c; //值不能改变
cout<<*p1<<*p2<<*p3<
const <数据类型> * p:限定值不能修改,表示指针指向常量
<数据类型> *const p:限定指向不能修改
3.引用const
#include
using namespace std;
int main()
{
int a = 1;
const int &d = a;
//d = 3; //错误:const限定引用不可修改
cout<
引用const经常用在函数参数里,节省空间时间
const限定的引用还有其他用途
#include
using namespace std;
int main()
{
int a = 1;
double b = 2.333;
//int &c = b; //错
const int &d = b;
cout<
4.内联函数
详情:https://blog.csdn.net/u011327981/article/details/50601800
解决调用函数执行效率低的问题
定义内联函数:
inline写在定义函数体前面,不是声明前面
效果就是编译时直接替代函数调用
内联对于小函数体(10行以内)较好大函数体可能会使效率降低
#include
using namespace std;
inline int Plus(int a,int b)
{
return a+b;
}
int main()
{
int a=1;
int b=2;
cout<
编译等价于
#include
using namespace std;
int main()
{
int a=1;
int b=2;
cout<<(a+b);
return 0;
}
5.函数重载&默认参数函数
(1)函数重载
方法:同名函数不同参
#include
using namespace std;
int Plus(int a,int b)
{
return a+b;
}
double Plus(double a,double b)
{
return a+b;
}
int main()
{
double a=1.111,b=2.222;
cout<
(2)默认参数函数
1.默认参数右边都要是默认参数
#include
using namespace std;
double Plus(double a=1.11,double b=2.22)
{
return a+b;
}
int main()
{
double a=1.111,b=2.222;
cout<
2.定义时默认参数必须在非默认参数右边
#include
using namespace std;
/*
double Plus(double a=1.11,double b) // 错误
{
return a+b;
}
*/
double Plus(double a,double b=2.22) //正确
{
return a+b;
}
int main()
{
return 0;
}
3.默认参数可以在声明或定义中定义,且只在其中一个定义
6.使用new和delete进行动态内存管理
用new的好处:对象可以调用构造函数
delete结束先调用析构函数再释放内存
new运算符返回该类型指针
#include
using namespace std;
class Demo
{
int a;
public:
Demo(int x):a(x){}
~Demo()
{
puts("析构");
}
int get()
{
return a;
}
};
int main()
{
int *p1 = new int;
delete p1;
int *p2 = new int[10];
delete []p2;
Demo *p3 = new Demo(2);
cout<get()<
(7)引用
1.引用类似指针只不过引用不能更改引用对象,指针能更改指向
2.引用必须在定义时初始化
2.类的构建
要求:
1.类的定义;
2.类对象的使用;
3.类成员变量的定义和使用;
4.类成员函数的定义和使用;
5.理解类的作用域;
6.理解类的声明;
7.理解类中private和public权限的声明依据。
解答:
1,2,3,4略
(5)作用域
#include
using namespace std;
class Demo
{
#define bign 99
public:
const int maxn;
Demo();
~Demo()
{
}
};
//在类体外用::作用域运算符定义函数
Demo::Demo():maxn(999){}
int main()
{
Demo d,*p=&d;
cout<maxn<
(6)类的声明
声明以后只能用于定义类指针
#include
using namespace std;
class Demo;
class Point
{
public:
Demo *p;
};
class Demo
{
public:
int a;
Demo(int x):a(x)
{
}
int get()
{
return a;
}
};
int main()
{
Demo d(1);
Point point;
point.p=&d;
cout<get()<
(7)类的成员属性(访问权限)
属性 | 访问范围 | 该种继承后的属性 |
---|---|---|
public | 该类中的函数,该类的对象,友元函数,子类函数 | 属性不变 |
protected | 该类的函数,子类函数,友元函数 | 父类protected与public变为protected.private仍为private |
private | 该类函数,友元函数 | 都变为private |
#include
using namespace std;
class Demo
{
private:
int a;
void out()
{
cout<
启示编写类是针对子类可能用到的private成员,留好接口(API)
3.构造函数与析构函数
要求
1.理解掌握this指针的作用和用法;
2.理解掌握构造函数的定义和作用;
3.掌握构造函数的使用;
4.理解掌握拷贝构造函数的定义和使用;
5.理解掌握构造函数的重载;
6.理解掌握析构函数的定义和使用。
解答
(1)this指针
指向该类自己的指针
可通过this指针访问该类成员
#include
using namespace std;
class Demo
{
public:
int row;
int col;
/* //错误:函数参数自己给自己赋值
Demo(int row,int col)
{
row=row;
col=col;
}
*/
Demo(int row,int col)
{
this->row=row;
this->col=col;
}
};
int main()
{
Demo d(1,2);
cout<
(2),(3)略
(4),(5)构造函数重载与拷贝构造函数
拷贝构造函数:拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:
- 通过使用另一个同类型的对象来初始化新创建的对象。
- 复制对象把它作为参数传递给函数。
- 复制对象,并从函数返回这个对象。
- 如果在类中没有定义拷贝构造函数,编译器会自行定义一个。
- 如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
#include
using namespace std;
class Demo
{
public:
int row;
Demo(int row)
{
this->row=row;
}
Demo(const Demo &tem)//构造函数重载,拷贝构造函数
{
this->row=tem.row;
}
};
int main()
{
Demo d1(1),d2(d1);
cout<
(6)析构函数
类的生命周期结束后自动调用析构函数(delete也会)
可以在析构函数中释放申请的内存...
#include
#include
using namespace std;
class Demo
{
public:
int *p;
Demo(int x)
{
p=(int *)malloc(sizeof(int)*x);
}
~Demo()
{
free(p);
cout<<"内存已释放"<
(4)对象传递和静态成员
要求
1.理解静态成员(静态数据成员、静态成员函数)的作用与使用;
2.理解友元(友元函数、友元类)的作用于使用;
3.理解常类型的使用。
解答
(1)静态成员
详情:http://c.biancheng.net/view/2228.html
- 静态成员变量:该类的所有对象公用一个
- 静态成员函数:只能访问静态成员,不需要通过对象调用,直接通过该类调用
#include
#include
using namespace std;
class Demo
{
public:
static int sum;
int a;
Demo(int x):a(x)
{
sum++;
}
static int get_sum() //静态成员函数
{
return sum;
}
};
int Demo::sum=0; //静态数据成员初始化
int main()
{
Demo d1(1),d2(2);
cout<
#include
#include
using namespace std;
class Demo
{
public:
static int sum;
int a;
Demo(int x):a(x)
{
sum++;
}
/* //错误
static int get_a()
{
return a;
} */
int get_sum()
{
//两种都可以
return this->sum;
return sum;
}
};
int Demo::sum=0; //静态数据成员初始化
int main()
{
Demo d1(1),d2(2);
cout<
(2)友元函数,友元类
声明函数或类为该类友元后,该函数或类可以访问该类的私有成员
#include
#include
using namespace std;
class Demo
{
public:
int get()
{
return a;
}
private:
int a;
void set(int x)
{
a=x;
}
friend class demo; //友元类
friend void set(int,Demo &); //友元函数
};
void set(int x,Demo &tem)
{
tem.a=x;
}
class demo
{
public:
void set(int x,Demo &tem)
{
tem.a=x;
}
int get(Demo &tem)
{
return tem.a;
}
};
int main()
{
Demo d;
set(1,d);
cout<
(3)常类型const
1.函数体前加const(const成员函数)
- 该函数不能修改类的数据成员
- 该函数只能调用const成员函数
2.函数前加const(返回值const函数),对于指针比较有用
3.参数const,间前面const用法
#include
using namespace std;
class Demo
{
public:
int a;
Demo(int x):a(x){}
void fix(int)const; //注意声明方式
const int* get1();
const int get2();
};
void Demo::fix(int x)const
{
//this->a=x; //不能修改类数据成员
int tem = x;
tem = 66;
}
const int* Demo::get1()
{
int ans = this->a;
return &ans;
}
const int Demo::get2()
{
int ans = this->a;
return ans;
}
int main()
{
Demo d(1);
d.fix(2);
//int *p=d.get(); //错误,返回的类型的指针是const
const int *p=d.get1();
cout<<*p<
5.派生与继承---单重派生
要求:
1.理解继承的含义以及声明;
2.理解共有派生、私有派生和保护派生的含义以及使用;
3.理解单派生类中构造函数和析构函数的调用顺序。
解答:
(1)(2)略
(3)派生类中构造函数析构函数调用顺序
- 类自己的数据成员构造函数顺序:
按定义顺序,与初始化列表顺序无关,再执行函数体(从上到下) - 派生类构造函数
- 由父到子
#include
using namespace std;
class grandfather
{
public:
grandfather()
{
cout<<"grandfather构造"<
运行结果:
grandfather构造
father构造
son构造
son析构
father析构
grandfather析构
- 多重继承只与继承时的顺序相关(从左到右),与初始化列表顺序无关
#include
using namespace std;
class father1
{
public:
father1()
{
cout<<"father1构造"<
运行结果
father1构造
father2构造
son构造
son析构
father2析构
father1析构
换成如下函数运行结果相同
class son:public father1,public father2
{
public:
son():father2(),father1()
{
cout<<"son构造"<
- 既有继承又有自己成员时:
先初始化继承,再按1的顺序初始化自己的成员
#include
using namespace std;
class father1
{
public:
father1()
{
cout<<"father1构造"<
运行结果
father1构造
father2构造
Demo1构造
Demo2构造
son构造
son析构
Demo2析构
Demo1析构
father2析构
father1析构
3.析构函数
顺序与构造函数正好相反
6.派生与继承---多重派生
要求:
1.理解多重派生的定义;
2.理解多重派生中构造函数与析构函数的调用顺序;
3.理解多重派生中虚拟基类的作用;
解答:
(1)多重派生
有多个父(基)类,派生类同时继承多个基类
(2)略,见上
(3)虚拟基类
虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
- 换个角度讲,虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。
以下为没有用虚基类的继承
继承以后C中有2个a分属于B1,B2
#include
using namespace std;
class A
{
public:
int a;
};
class B1:public A
{
public:
int b1;
};
class B2:public A
{
public:
int b2;
};
class C:public B1,public B2
{
public:
C(int aa,int bb1,int bb2,int cc)
{
//a = aa; //有2个a,歧义
B1::a = aa; //通过::访问2个不同的a
B2::a = aa+10;
b1= bb1;
b2= bb2;
c = cc;
}
int c;
};
C demo(1,2,3,4);
int main()
{
cout<
使用虚基类
C中只有1个a了,被B1,B2分享公用
#include
using namespace std;
class A
{
public:
int a;
};
class B1:virtual public A
{
public:
int b1;
};
class B2:virtual public A
{
public:
int b2;
};
class C:public B1,public B2
{
public:
C(int aa,int bb1,int bb2,int cc)
{
a = aa;
b1= bb1;
b2= bb2;
c = cc;
}
int c;
};
C demo(1,2,3,4);
int main()
{
cout<
7.多态性---函数与运算符重载
要求:
1.理解动态联编和动态联编的概念;
2.理解掌握成员函数方式运算符重载;
3.理解掌握友元函数方式运算符重载;
4.理解掌握++、--、=运算符的重载。
解答:
(1)动态连编
编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序运行时才能确定将要调用的函数,为此要确切知道该调用的函数,要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作被称为动态联编。
虚函数
- 通过基类对象指针是无法访问派生类的同名函数的
- 虚函数用途:通过基类访问派生类定义的函数,指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。
- 基类声明的虚函数,在派生类中及时不用virtual,仍是虚函数
- 虚函数只能通过指针/引用实现多态
1.定义一个函数为虚函数,不代表函数为不被实现的函数(可以有自己的实现)
2.定义它为虚函数是为了允许用基类的指针来调用子类的这个函数(提供了基类调用子类函数的方式)
3.定义一个函数为纯虚函数,代表函数没有被实现(声明后面接=0,例如:virtual func() = 0 此时派生类必须要实现此虚函数)
相当于规范要求派生类必须实现这个函数
4.具有纯虚函数的类是抽象类,不能用于生成对象(即不能实例化),只能派生,它派生的类如果没有实现纯虚函数,那么他的派生类还是抽象类。
以上内容来自:https://www.cnblogs.com/GyForever1004/p/8443241.html
只有虚析构函数,没有虚构造函数
用new创建派生类对象时,基类指针指向该对象,delete时通过静态联编,调用基类析构函数而不调用派生类的,产生内存泄漏.
设置成虚析构函数时,会通过动态联编,调用派生类析构函数
使用虚函数的情况
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的。从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现。通过这样的方法,就可以将对象的行为抽象化。
参考:https://www.cnblogs.com/eilearn/p/9415786.html
#include
using namespace std;
class A //抽象类
{
public:
A()
{
cout<<"A constructed"<fun();
cout<sum(1,2)<
(2)(3)(4)两种方式进行运算符重载
成员函数||友元函数:
成员函数重载比友元函数重载少一个参数(左侧的参数是该对象本身)
流运算符必须通过友元函数重载 双目运算符重载 常见单目运算符重载 其余重载详见:https://blog.csdn.net/liuyuchen282828/article/details/96474317 1.理解掌握运算符[]、()的重载; 下标运算符[ ]必须以成员函数的形式进行重载 格式: 以上第一种不仅可以访问元素,还可以修改元素. <2>类型转换: 格式: 1.能够使用C++模板机制定义重载函数。
因为<<或>>左侧是cin,cout不是对象本身,除非要写成a<#include
#include
8.多态性--类型转换和虚函数
要求:
2.理解类型转换,掌握类型转换函数的设计和使用;
3.理解和掌握虚函数的作用;
4.掌握利用虚函数实现C++的运行时多态性;
5.理解纯虚类和抽象类。解答:
1.[]和()重载
(1)[]重载:
返回值类型 & operator[ ] (参数);
或:
const 返回值类型 & operator[ ] (参数) const;
第二种只能访问元素,适用于const对象#include
(2)重载()
<1>一般带参()运算符#include
operator type(){return type对象;}#include
(2),(3),(4),(5) 前面均有,略
8.模板类
要求:
2.能够实例化及使用模板函数。
3.能够实例化和使用模板类。
4.应用标准C++模板库(STL)通用算法和函数对象实现查找和排序。解答: