主要本人期末复习使用,朋友们可以参考。
目录
cpp-09
- 预处理器封装
#ifndef A_H
#define A_H
class A{ int a;}
#endif
- sizeof(类对象)
sizeof的结果将大于等于类中数据成员的大小
an object name (对象名): 点操作符
a reference to an object (对象引用): 点操作符
a pointer to an object (对象指针): 箭头操作符
- 缺省构造函数
- 函数重载
C++允许函数同名,但要求参数不同(数量、类型、顺序)。
Class A
{ int x, y;
public:
A( )
{ x=y=0; }
A( int x1 )
{x=x1;y=0;}
A( int x1,int y1 )
{x=x1;y=y1;}
}
- 析构函数自动调用的两种情况
(1)如果一个对象被定义在一个函数体内,则当这个函数结束时,该对象的析构函数被自动调用;
(2)当一个对象是使用new运算符被动态创建的,在使用delete运算符释放它时,delete将会自动调用析构函数
- 各类对象的生存周期
- 默认实参必须是函数参数列表中右端(尾部)的参数,即如果某个参数设定了默认实参,那么该参数右边的所有参数都必须具有默认实参!
// OK
int boxVolume( int length = 1, int width = 1, int height = 1 );
int boxVolume( int length, int width = 1, int height = 1 );
int boxVolume( int length, int width, int height = 1 );
// ERROR
int boxVolume( int length = 1, int width, int height = 1 );
int boxVolume( int length, int width=1, int height );
// ERROR: missing default parameter for parameter x
- 显式传递给函数的实参是从左至右给形参赋值
int boxVolume( int length=1, int width=1,int height=1 );
boxVolume(); // length=1, width=1, height=1
boxVolume(10); // length=10, width=1, height=1
boxVolume(10,5); // length=10, width=5, height=1
boxVolume(10,5,2); // length=10, width=5, height=2
cpp-10
- 常成员函数(两处都要声明)
void printUniversal() const;
void Time::printUniversal() const { … }
class Time
{
public:
Time( int = 0, int = 0, int = 0 );
void setTime( int, int, int );
void setHour( int );
void setMinute( int );
void setSecond( int );
int getHour() const;
int getMinute() const;
int getSecond() const;
void printUniversal() const;
void printStandard();
private:
int hour; int minute; int second;
};
void Time::test(Time &another) const
{
minute = 20;
// 不能修改object
printStandard();
// 不能调用non-const成员函数
another.minute = 20;
// OK,非同一object
another.setHour(6);
// OK
}
- 所有的类成员都可以用构造函数初始化列表进行初始化,而以下情况只能如此:
class Test{
public:
Test( int a ){ num = a;
cout<<a<<endl; }
private:
int num;
};
class Test2{
public:
Test2(int a, int b): t(a) { num = b;
cout<<b<<endl;}};
private:
Test t;
int num;
};
void main(){
Test2 test(10, 20);
}
10 20
class Test{
public:
Test( int a=0 ){ num = a;
cout<<a<<endl; }
private:
int num;
};
class Test2{
public:
Test2(int a, int b) { num = b;
cout<<b<<endl;}
private:
Test t;
int num;
};
void main(){
Test2 test(10, 20);
}
0 20
- 友元函数
.运算符比*运算符优先级高
- 函数的级联调用:
class Time
{
public:
Time( int = 0, int = 0, int = 0 );
Time &setTime( int, int, int );
Time &setHour( int );
Time &setMinute( int );
Time &setSecond( int );
void print() const;
private:
int hour;
int minute;
int second;
};
class Time2
{
public:
Time2( int = 0, int = 0, int = 0 );
Time2 setTime( int, int, int );
Time2 setHour( int );
Time2 setMinute( int );
Time2 setSecond( int );
void print() const;
private:
int hour;
int minute;
int second;
};
t.setHour( 18 ).setMinute( 30 ).setSecond( 22 );
t.setMinute( 30 ).setSecond( 22 );t.setSecond( 22 );
- 传引用或传拷贝对比:
- 动态数组
int size = 10;
int *grades = new int[size];
delete [ ] gradesArray;
对象的指针数组
Time ** timePtr = new Time*[5];
for (int i =0; i<5; i++) timePtr[i] = new Time();
for (int i =0; i<5; i++) delete timePtr[i];
delete [] timePtr;
- 类的const类型成员
类的static类型成员
cpp-11
- 运算符重载:
定义重载的运算符(可视为特殊函数)就像定义函数(全局/成员),区别是该函数的名称是
operator@
其中operator是关键词,@是被重载的运算符,如:
HugeInt operator+(const HugeInt& a);
- 流输入输出的重载稍微不太一样
friend ostream& operator<<(ostream&, const HugeInt&);
ostream& operator<<(ostream& cout, const HugeInt& x)
{
int i = 0;
for (; i <= 29; i++)
{
if (x.integer[i] != 0)
break;
}
if (i == 30)
cout << "0";
for (; i <= 29; i++)
{
cout << x.integer[i];
}
return cout;
}
HugeInt operator=(const HugeInt&);
HugeInt operator+(const HugeInt&) const;
HugeInt HugeInt::operator=(const HugeInt& x){
}
HugeInt HugeInt::operator+(const HugeInt& x) const
{
}
- 有动态数据成员时,必须自定义拷贝构造函数(深拷贝)和析构函数
d1传给函数里的d一次
Date d2=d 第二次
return d2第三次
- 转换构造函数
- strcpy()
char * strcpy(char *dst,const char *src)
{
if((dst==NULL)||(src==NULL))
return NULL;
char *ret = dst; //[1]
while ((*dst++=*src++)!='\0'); //[2]
return ret;//[3]
}
关于空3:
由strcpy代码可知,实际上的代码复制,是把开始传入的指针作为起点
cpp-12 继承
cpp-13 多态
派生类virtual可省略。只要基类声明函数为虚函数,则所有派生类的该函数均为虚函数
基 类
class Shape{
public:
virtual void draw() const;
};
派生类
class Rectangle : public Shape{
void draw() const;
};
只有通过引用或指针来访问对象的虚函数时才进行动态绑定。
通过引用或指针访问对象的非虚成员函数,采用静态绑定。(与句柄类型的成员函数代码绑定)
通过“类名+::”访问对象成员函数,也采用静态绑定。
cpp-14 文件处理
见C++ 文件处理的简单应用(模拟从各种客户端访问一个网站)
- 创建ofstream对象
对于已创建的文件对象,使用成员函数打开文件
in :(从文件读取) 打开方式只要含in,如文件不存在则返回失败。在打开为输入输出方式时(同时用out),编程应注意判断是否失败,失败时千万不可再写入文件。
out: (写入文件) 如文件不存在,则建立新文件,如文件存在,如果同时未设定app, in,则文件清空。
fstream iofile;//既输入又输出用
iofile.open(“myfile.txt”,ios::in|ios::out);
- 判断打开文件是否成功
打开文件时应该判断是否成功,若成功,文件流对象值为非零值,不成功为0(NULL),文件流对象值就是指它的地址。
//打开一个文件完整的程序
int main()
{
fstream iofile(”myfile.txt”,ios::in|ios::out);
if(!iofile) { //“!”为重载的运算符
cout<<”不能打开文件:”<<”myfile,txt”<<endl;
return -1;
} //失败退回操作系统
}
- 文件的打开与关闭
打开:
使用文件流对象的成员函数打开一个磁盘文件。
iofile.open(“myfile.txt”,ios::in|ios::out);
也可直接通过构造函数打开文件:
fstream iofile(”myfile.txt”,ios::in|ios::out);
关闭:
三个文件流类各有一个关闭文件的成员函数 :
使用很方便,如:iofile.close();
cpp-17 异常处理
- 异常处理模板:
解决思路:C++提供了一些内置的语言特性来抛出(throw)异常,用以通知“异常已经发生”,然后由预先安排的程序段来捕获(catch)异常,并对它进行处理。
//抛掷异常的程序段
......
throw 表达式;
......
//捕获并处理异常的程序段
try
{复合语句}
catch(异常类型声明1)
{复合语句}
catch(异常类型声明2)
{复合语句}
…
- 头文件:#include <stdexcept>
- 易错
- 虚函数中的异常指定:
派生类的虚函数的异常指定必须与基类虚函数的异常一样或更严格。因为当派生类的虚函数被指向基类类型的指针调用时,保证不会违背基类成员函数的异常规范。
class CBase{
public:
virtual int fun1(int) throw();
virtual int fun2(int) throw(int);
virtual string fun3() throw(int,string);};
class CDerived:public CBase{
public:
int fun1(int) throw(int);
//错!异常规范不如throw()严格
int fun2(int) throw(int); //对!有相同的异常规范
string fun3() throw(string); }
//对!异常规范比 throw(int,string)更严格
cpp-15 STL
cpp-18 类模板
- template <类型形参表>
返回值类型 函数名(形参表)
{
//函数定义体
}
<类型形参表>可以有一到若干个类型形参,各形参前需要加上typename/class关键字,表示传递类型,当有多个形参时,各形参间用逗号分隔。
<类型形参表>中的每个形参表示一种数据类型。函数模板“形参表”中至少有一个形参的类型必须用<类型形参表>中的形参来定义。
函数模板只是说明,不能直接执行,需要特化为模板函数后才能执行。
- 函数模板重载
#include <iostream>
using namespace std;
template <class T>
void print (const T &a, int b) {cout << "first function called!"<< endl;}
template <class T, class T1>
void print (const T &a, T1 b) {cout << "second function called!";}
template <class T, class T1>
void print (const T &a, int c, T1 b) {cout << " third function called!";}
template <class T, class T1>
void print (const T &a, T1 b, int c) {cout << “fourth function called!";}
void print (int a, int b) {cout << " fifth function called!"<< endl;}
void print (int a ) {cout << “sixthfunction called!"<< endl;}
print(1,2); print(1.1, 2);
- 类模板定义:
template <typename <类型参数>> //模板声明
class <类名> // 类定义
{
……
};
每个“类型形参”前必须加typename or class关键字,对类模板进行实例化时,代表某种数据类型;也可以是普通数据类型形参,实例化时代表具体数据
例如:
template < typename arg1, int arg2, typename arg3>
class myclass
{ arg1 buffer[arg2];
arg3 x; //类的定义体
};
类模板中成员函数可以放在类模板的定义体中(此时与类中的成员函数的定义方法一致)定义,也可以放在类模板的外部来定义,格式为:
template <类型形参表>
函数返回类型 类模板名<类型名表>::成员函数(形参)
template < typename arg1, int arg2, typename arg3>
void myclass<arg1,arg2,arg3>::print() {}
- 类模板使用注意:
如:Myclass<int> a;
#include <iostream>
using namespace std;
template <typename T>
class AnyType
{ T x, y;
public:
AnyType(T a, T b): x(a), y(b){}
T GetX(){return x;}
T GetY(){return y;}
};
int main()
{
AnyType <int> i (1, 2);
AnyType <double> d (1.5, 2.7);
AnyType <char> c ('a', 'b');
AnyType <char *> s ("Hello", "template class");
cout << "整型类:" << i.GetX() << ", " << i.GetY() << endl;
cout << "双精度类:" << d.GetX() << ", " << d.GetY() << endl;
cout << "字符类:" << c.GetX() << ", " << c.GetY() << endl;
cout << "字符串类:" << s.GetX() << ", " << s.GetY() << endl;
return 0;
}
- 类模板中的static数据成员
template <typename T>
class A
{ static int x;
};
template < typename T> int A<T>::x=0;
A<int> a1,a2; // a1和a2共享一个x
A<double> b1,b2; // b1和b2共享一个x