目录
前言
一、复合类
二、友元函数和静态成员
三、多态
四、运算符重载
五、类模板的类外实现
六、杂七杂八
前言
不知不觉一个学期又过去了,我也马上就要大二了,在网课的荼毒和自己的摆烂下,导致不能单杀C艹,特此在这里攻克一下自己的薄弱点。
一、复合类其实把一个类中的另一个类当作普通数据成员就好了,保险起见在函数参数里加“&“。
二、友元函数和静态成员1.静态成员
类的所有对象共用 一个存储空间 描述这一类的对象 共有的数据例子:总分,统计时的数字。
class CMan {
string szName;//区分不同的人
float height, weight;//保存一个人的身高和体重信息
float figureQuota; //保存一个人的体重指标信息
static int peopleTotal; //保存群体的总人数
static float quotaSum; //保存群体的全部体重指标之和
public:
CMan(string name, float h, float w);
float computeQuota();//计算体重指标 public :
float getDiffToAverage(); //查看体重指标与群体平均指标的差
float getQuota();//查看体重指标
~CMan();//消除一个人对群体平均体重指标的影响
};
int CMan::peopleTotal=0;
float CMan::quotaSum=0;//别忘了声明,=0是为了一般情况下的计数
静态成员是属于整个类的,而不是属于该类的特定的对象的。
(1)静态成员的初始化:
只要在类中定义了静态数据成员,即使不定义对象,也为静态数据成员分配空间。
静态数据成员在程序编译时分配空间,到程序结束时才释放空间。
静态数据成员的初始化只能在类体外进行,若不初始化,系统会默认赋值(比如数值型数据默认为0)。
(2)静态成员常用的场合
用来保存流动变化的对象个数。
作为一个 标志 ,指示一个特定的动作是否发 生。一个指向链表第一个成员的指针。
class A
{ int a;
static int num;
public:
A():a(1){num++;cout<<"Constructing...."<<" "
<
运行结果:
Constructing.... 1
Constructing with reference....2
Coping Constructing...3
Destructing...3
Destructing...2
Destructing...1
2.静态成员函数
静态成员函数不能访问非静态数据成员和非静态成员函数,它只能访问静态数据成员和其他的静态成员函数
静态成员函数的作用是为了能处理静态数据成员。
#include
#include
using namespace std;
const double PI=3.1415;
class Cylinder
{public:
Cylinder(double r):radius(r){};
static double getHeight(){return height;};
void static setHeight(double h){height=h;};
double volume();
private:
double radius;
static double height; //把height定义为静态成员
};
double Cylinder::volume()
{ return PI*radius*radius*height;}
double Cylinder::height=10; //在类体外对静态数据成员height初始化
int main()
{
cout<
别死脑筋,构造函数参数爱写几个写几个,不一定全写
3.友元(其实能不用就不用)
(1)为了让类外的函数或另一个类,可以访问类中的私有成员,可以将它们声明为友元。
友元的声明只能出现在类定义的内部,以关键字friend声明。
友元不是本类的成员,所以不受访问控制影响。
友元的引入破坏了类的封装性和数据的隐藏性,请小心使用。
class Time {
int hour;
int minute;
int sec;
public: Time(int,int,int);
friend void display(Time &); //声明display为Time类的友元
};
Time∷Time(int h,int m,int s) //构造函数
{ hour=h; minute=m; sec=s; }
void display(Time& t)
//友元不是Time类的成员,所以只能通过对象访问私有成员
{ cout<
(2)将另一个类的成员函数声明为友元
class Date; //对Date类的提前引用声明
class Time {
public:
void display(Date &);
//display是成员函数,形参是Date类对象的引用
};
class Date {
public:
friend void Time∷display(Date &);
//声明Time中的display函数为友元成员函数
};
友元类说实话没大用,就不码字了(嘻嘻)。
三、多态在程序中同一符号或名字在不同情况下具有不同解释的现象称为多态性。
1.虚拟继承(其实这是属于继承的,不过这个和继承风格不太搭)
主要是在探究解决二义性的方法:(1)使用作用域运算符“::”(2)重定义有冲突的成员
虚拟继承可解决重复继承时继承多次简接基类,使公共基类的成员在其派生类中只产生一个拷贝
虚基类:如果某个基类被声明为虚基类,那么在被重复继承时,在派生类对象实例中只存储一个副本(若不声明为虚基类,就会出现多个副本)。
在从基类派生新的类时,将这个基类用virtual关键字说明为虚基类。例如:
class BASE1 : virtual public BASE
某构造函数的实现:
CStudentOnJob(string _name, int _stuNo, string _title, string _research):
CPerson(_name),
CStudent(_name, _stuNo),
CTeacher(_name, _title),
research(_research)
{ cout<<"CStudentOnJob Constructor"<
构造方法执行过程:如果缺省,Cperson就会调用不带参数的构造方法,姓名并没有赋值进去。
1. 使用参数初始化 Cperson 部分; 2. 构造 CStudent 部分,忽略 CStdent 用于 Cperson 的部分 3. 构造 CSTeacher 部分,忽略 CSTeacher 用于 Cperson 的部分 4. 构造 CStudentOnJob 部分静态联编,是指这种联编在编译阶段完成的,即在编译阶段就必须确定标识符(函数名)与代码之间的对应关系。由于联编过程是在程序运行前完成的,所以又称为早期联编。
静态联编能够实现编译时多态。
动态联编是指根据目标对象的动态类型(而不是静态类型)在程序运行时(而不是在编译阶段)将函数名绑定到具体的函数实现上。
动态联编可以实现运行时多态。
2.纯虚函数: virtual <函数返回类型> <函数名>(<参数表>) = 0;
3.抽象类:
包含纯虚函数的类称做抽象类。(我才知道~)
由于无法实例化一个含纯虚函数的抽象类,因而不能创建抽象类的对象。
抽象类不能用作变量类型、函数返回和显式转换的类型,但可定义指向抽象类的指针或引用。
四、运算符重载其实内容很简单,怕自己忘了怎么声明再提一嘴
CComplex& operator += (const CComplex& r_c)
用友元函数重载(参数中必须有一个类型为类对象或类对象引用)
friend Increase & Increase::operator++(int) //(后增量)
friend Increase operator++(Increase& a, int)
输入输出运算符重载:
friend ostream & operator << (ostream & stream, const 类名 &obj )
{ stream<<"注意区分单双引号"<
friend istream & operator >> ( istream &stream, 类名 &obj )
{ stream>>obj.a;// 函数体
return stream;
}
用数组判断是否出界”[]“运算符:
#include
#include
using namespace std;
const int SIZE=10;
class VECTOR{
protected:
int table[SIZE];
public:
VECTOR(){
for(int i=0;i<=SIZE-1;i++)
table[i]=i;}
int& operator[ ](int index){
if((index<0)||(index>SIZE-1)){
cout<<"Index out of bounds\n";
exit(0);
}
return table[index];
}
};
int main()
{
VECTOR label;
cout<
(为啥不用stl?)
五、类模板的类外实现其实导致这个东西麻烦的原因还是老生常谈的二义性问题,所以好好给变量和函数起名字是辣么的重要(doge)
template
class List{
protected:
TYPE* vector;
int size;
public:
List (int length); //构造函数
~List( ) { delete [ ] vector; } //析构函数
TYPE& operator[ ](int index);
};
template
List< TYPE >::List (int length)
{ vector=new TYPE[length];
size=length;
for(int i=0;i
TYPE& List< TYPE >::operator[](int index)
{ return vector[index];
}
template
class MUTI_PARA{
TYPE1 first;
TYPE2 second;
public:
MUTI_PARA(TYPE1 x, TYPE2 y){ first=x;second=y; }
void show(){ cout< obj1(2, 3.14);
MUTI_PARA obj2(“Are you sure?”, ’Y’);
obj1.show( );
obj2.show( );
}
其实用类模板在之后的工作和日常应用中还是挺方便的,那么几行代码就能省去很多的类型转换以及重复声明。
类模板的实例化:用某一个具体的数据类型替 代类模板中的模板参数。
类模板中的模板参数尚未确定,故不能直接 利用类模板创建对象。
template
class MUTI_PARA{
TYPE1 first;
TYPE2 second;
public:
MUTI_PARA(TYPE1 x, TYPE2 y){ first=x;second=y; }
void show(){ cout< obj1(2, 3.14);
MUTI_PARA obj2(“Are you sure?”, ’Y’);
obj1.show( );
obj2.show( );
}
六、杂七杂八
1.A **a=new A*[t];//在这里写句二级指针,二级指针指向指针数组
for(int i=0;i
Cylinder *c1=new Cylinder[3];
Cylinder *c2=new Cylinder(2,3);
Cylinder **c3=new Cylinder*[3];
解析:
1、c1是对象指针,指向具有3个对象的动态数组。
2、c2是对象指针,指向一个动态对象,该对象初始化值为(2,3)。
3、c3是二级对象指针,指向一个含3个指向对象的指针数组。
CSample array1[2]; cout<
2.拷贝构造函数
不允许 有形如 X( X r) 的拷贝构造函数 即使 缺省的构造函数 不存在 , 缺省的拷贝构造函数 仍然 存在 。 程序如果 没有定义拷贝构造函数 ,那么编译器 生成 缺省的拷贝构造函数 。 如果 定义了 自己的拷贝构造函数 ,则 缺省的拷贝构造函数 不存在 。 当参数是一个对象时,推荐使用对象的引用,如果担心函数改变参数的值,可以在参数前加 const 。参数前加 const 会有一个限制,只能调用 const 类型的成员函数 重点及易忽略的地方:深拷贝 深拷贝 :为对象中的 指针成员 申请必要的内存 ,在成功获得内存空间后,再把 被复制对象的指针所指向的内存中的值 拷贝到 新申请的内存 中。 3.析构函数若对象是动态生成的,则不会自动调用析构函数,而是要用delete来手动调用。
4.this指针
Cylinder compare(Cylinder &c)
{ if(volume()>c.volume())
return *this;
else
return c;
}
5.常对象、常成员函数与常数据成员
(1)常对象
const 类名 对象名
const Cylinder c1;
声明常对象时,必须同时初始化,且对象中的数据成员在程序的其他地方不能被重新赋值。
一个对象被声明为常对象,则不能调用该对象的非const型的成员函数,以避免这些函数会修改对象中的数据成员的值。
验证小程序:const对象不能调用非const函数
#include
#include
using namespace std;
class A
{ private:
int x;
public:
A(int x1=0):x(x1){cout<
(2)常成员函数
类型 函数名(参数表)const
double getHeight() const;
常成员函数只能引用本类中的数据成员,而不能修改它, 也不能调用该类中没有const修饰的成员函数。
静态成员函数不能声明为常成员函数。
(3)常数据成员
常数据成员的值是不能改变的。
可通过构造函数的参数初始化列表或定义时直接赋值对常数据成员进行初始化。
为啥子要用const成员呀?
如果一个类中,某些 数据成员的值不允许改变 ,可将它们声明为 const ; 任何 不会修改数据成员的函数 都应该声明为 const 类型。(其实这句话挺重要的) 如果在编写 const 成员函数时,不慎修改了数据 成员,或者调用了其它非 const 成员函数,编译 器将指出错误,这无疑会 提高程序的健壮性 。(奇奇怪怪)6.来个类型转换
#include
using namespace std;
class Point3D;
class RMB
{ int yuan,jiao,fen;
public:
RMB(int y=0,int j=0,int f=0):yuan(y),jiao(j),fen(f){}
operator double(){return yuan+jiao*0.1+fen*0.01;}
operator int(){return yuan*100+jiao*10+fen;}
operator Point3D();
void print(){cout<
结语:
就先写这么多吧,反正自己复习了一遍好多了,之后再翻回来看看,啾咪~
祝大家期末顺利,放假狂卷((●'◡'●))
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)