目录
定义成员函数
内联成员函数
构造函数
析构函数
new和malloc、free和delete的区别和联系
静态成员
静态数据成员
静态成员函数
友元
拷贝构造函数
调用拷贝构造函数的三种情况
运算符重载
重载运算符
重载=运算符
拷贝构造函数和重载=函数的区别
重载++运算符
重载比较运算符
类的组合
构造函数析构函数调用顺序
继承、多态、虚函数
类的继承与派生
保护成员与类的访问
构造函数和析构函数
多态和虚函数
纯虚函数
默认情况下类的成员是私有的,而结构体的成员时共有的。
私有成员函数只能被本类的其它函数所调用.
成员函数在类之外定义的常规方式: 可以将参数传给私有成员变量。
<返回值类型> <类名>::<函数名> ( 参数列表 ) { }
void Rectangle::setData(float w, float l )
{
width = w;
length = l;
}
函数体出现在类的定义中,就叫做内联函数,一般是一些getset
class Clock
{
public:
Clock (int NewH, int NewM, int NewS);//构造函数
void SetTime(int NewH, int NewM, int NewS);
void ShowTime();
private:
int Hour,Minute,Second;
};
//构造函数实现
Clock::Clock(int NewH, int NewM, int NewS)
{
Hour= NewH;
Minute= NewM;
Second= NewS;
}
//建立对象时构造函数的作用:
void main()
{
Clock c (0,0,0); //隐含调用构造函数,将初始值作为实参。
c.ShowTime();
}
class PersonInfo {
char *name; int age;
public:
PersonInfo(char *n, int a) {
name = new char[strlen(n) + 1];
strcpy(name, n); age = a;
}
~PersonInfo ( ) { delete [ ] name; }
char *getName ( ) { return name; }
int getAge ( ) { return age; }
};
1、new 是c++中的操作符,malloc是c 中的一个函数
2、new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员的工作,同样free也不会调用析构函数
3、内存泄漏对于malloc或者new都可以检查出来的,区别在于new可以指明是那个文件的那一行,而malloc没有这些信息。
题目:
假定CMyClass是个类,则执行CMyClass a(4),b[3],*p[2]
调用该类的构造函数 4 次
a(4)1次+b[3]3次,没有初始化的指针为空,不指向任何对象,也不调用构造函数。
//在Aux类中,访问Budget类中的成员
void addBudget( float, Budget &);
//在Budget类中
friend void Aux::addBudget(float, Budget &);
//外部
void Aux::addBudget(float b, Budget &div)
{
auxBudget = b;
div.corpBudget += auxBudget;
}
可以把一个类定义成友元:friend class Aux
拷贝构造函数是一个特殊的构造函数,当定义一个对象并采用同类型的另一个对象初始化时会自动调用。
PersonInfo person1("Jones", 25);
PersonInfo person2 = person1; // ???
PersonInfo ( const PersonInfo &obj)
{
name = new char [strlen(obj .name) + 1];
strcpy(name, obj.name);
age = obj.age;
}
void main(void)
{ Point A(1,2);
Point B(A); //拷贝构造函数被调用
cout<
void fun1(Point p)
{ cout<
Point fun2()
{ Point A(1,2);
return A; //调用拷贝构造函数
}
void main()
{
Point B;
B=fun2();
}
多态:多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。
多态的实现:-函数重载 -运算符重载 -虚函数
声明形式:函数类型 operator 运算符(形参){ ......}
重载为类成员函数时,参数个数=原操作数个数-1 (后置++、--除外)
重载为友元函数时,参数个数=原操作数个数,且至少应该有一个自定义类型的形参。
类成员:
complex operator + (complex c2); //+重载为成员函数
complex operator - (complex c2); //-重载为成员函数
complex complex::operator +(complex c2) //重载函数实现
{
complex c(real+c2.real,imag+c2.imag);
return c;
}
//或:return complex(real+c2.real,imag+c2.imag)
友元:
friend complex operator + (complex c1,complex c2); //运算符+重载为友元函数
friend complex operator - (complex c1,complex c2); //运算符-重载为友元函数
complex operator + (complex c1,complex c2) //运算符重载友元函数实现
{ return complex(c2.real+c1.real, c2.imag+c1.imag);
}
complex operator - (complex c1,complex c2) //运算符重载友元函数实现
{ return complex(c1.real-c2.real, c1.imag-c2.imag);
}
#include
#include
class PersonInfo {
char *name;
int age;
public:
PersonInfo(char *n, int a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
age = a;
}
PersonInfo(const PersonInfo & obj ) {
name = new char[strlen(obj.name) + 1];
strcpy(name, obj.name);
age = obj.age;
}
~PersonInfo( ) { delete [ ] name; }
char *getName( ){ return name; }
int getAge( ) { return age; }
PersonInfo operator=(const PersonInfo &right){
delete [ ] name;
name = new char[strlen(right.name)+ 1];
strcpy(name, right.name);
age = right.age;
return *this;
}
};
this指针:一个隐含的内嵌指针,以隐含参数的形式传递给非静态的成员函数.
复制构造函数又称拷贝构造函数,它与赋值操作符间的区别体现在以下几个方面
1.从概念上区分:
复制构造函数是构造函数,而赋值操作符属于操作符重载范畴,它通常是类的成员函数
2.从原型上来区分:
复制构造函数原型ClassType(const ClassType &);无返回值
赋值操作符原型ClassType& operator=(const ClassType &);返回值为ClassType的引用,便于连续赋值操作
3.从使用的场合来区分:
复制构造函数用于产生对象,它用于以下几个地方:函数参数为类的值类型时、函数返回值为类类型时以及初始化语句,例如(示例了初始化语句,函数参数与函数返回值为类的值类型时较简单,这里没给出示例)
ClassType a;
ClassType b(a); //调用复制构造函数,初始化时拷贝
ClassType c = a; //调用复制构造函数
而赋值操作符要求‘=’的左右对象均已存在,它的作用就是把‘=’右边的对象的值赋给左边的对象
ClassType e;
Class Type f;
f = e; //调用赋值操作符,fe已存在
4.当类中含有指针成员时,两者的意义有很大区别
复制构造函数需为指针变量分配内存空间,并将实参的值拷贝到其中;而赋值操作符它实现的功能仅仅是将‘=’号右边的值拷贝至左值,在左边对象内存不足时,先释放然后再申请。当然赋值操作符必须检测是否是自身赋值,若是则直接返回当前对象的引用而不进行赋值操作
关于啥时候要用const:【C++】运算符重载关于const的分析(超详细)_萌宅鹿同学的博客-CSDN博客_c++ const 重载
FeetInches operator++( );
FeetInches operator++( int );
FeetInches FeetInches::operator++( )
{
++inches;
simplify ( );
return *this;
}
FeetInches FeetInches::operator++(int)
{
FeetInches temp(feet, inches);
inches++;
simplify( );
return temp;
}
int operator> (const FeetInches & );
int operator< (const FeetInches & );
int operator== (const FeetInches & );
int FeetInches::operator> (const FeetInches &right )
{
if (feet > right.feet)
return 1;
else
if (feet==right.feet && inches> right.inches)
return 1;
else return 0;
}
int FeetInches::operator< (const FeetInches &right)
{ if (feet < right.feet)
return 1;
else
if (feet == right.feet && inches < right.inches)
return 1;
else return 0;
}
int FeetInches::operator==(const FeetInches &right)
{
if (feet == right.feet && inches == right.inches)
return 1;
else return 0;
}
类中的成员数据是另一个类的对象。
声明形式:
类名::类名(对象成员所需的形参,本类成员形参)
:对象1(参数),对象2(参数),...... { 本类初始化 }
继承:保持已有类的特性而构造新类的过程,被继承的已有类称为基类(或父类)
派生:在已有类的基础上新增自己的特性而产生新类的过程,派生出的新类称为派生类。
继承的目的:实现代码重用。
派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造。
声明方式:class 派生类名:继承方式 基类名 { 成员声明; }
class Grade {
char letter;
float score;
void calcGrade( );
public:
void setScore(float s) { score = s; calcGrade(); }
float getScore( ) { return score; }
char getLetter( ) { return letter; }
};
class Test : public Grade {
int numQuestions; //问题个数
float pointsEach; //每个问题分数
int numMissed; //错误问题数
public:
Test( int, int );
};
// q = 问题个数, m = 错误问题数.
//********************************************
Test::Test(int q, int m)
{ float numericGrade;
numQuestions = q;
numMissed = m;
pointsEach = 100.0 / numQuestions;
numericGrade = 100.0 - ( numMissed * pointsEach );
//派生类可以调用基类成员,基类不能调用派生类成员
setScore(numericGrade);
}
// 主函数里
// 定义一个Test对象
Test exam(questions, missed);
cout.precision(2);
cout << "\n The score is " << exam.getScore();
cout << "\n The grade is " << exam.getLetter();
基类的保护成员和私有成员类似,但是可以被派生类所访问。
private |
基类私有成员对于派生类来说是不可访问的. 基类保护成员在派生类中变成私有成员 基类公有成员在派生类中成为私有成员 |
protected |
基类私有成员对于派生类来说是不可访问的. 基类保护成员在派生类中成为保护成员 基类公有成员在派生类中成为保护成员 |
public |
基类私有成员对于派生类来说是不可访问的. 基类保护成员在派生类中成为保护成员 基类公有成员在派生类中成为公有成员 |
调用顺序:基类的构造函数先于派生类的构造函数执行。 析构函数调用顺序相反。
传递参数:派生类的构造函数需传递参数给基类的构造函数。
Cube::Cube(float w, float l, float h) : Rect(w, l )
{ height = h ; volume = area * height ;
}
#include
class B0 //基类B0声明
{
public: //外部接口
virtual void display()
{cout<<"B0::display()"<display(); }
void main() //主函数
{ B0 b0, *p; //声明基类对象和指针
B1 b1; //声明派生类对象
D1 d1; //声明派生类对象
p=&b0;
fun(p); //调用基类B0函数成员
p=&b1;
fun(p); //调用派生类B1函数成员
p=&d1;
fun(p); //调用派生类D1函数成员
}
程序的运行结果为:
B0::display()
B1::display()
D1::display()
纯虚函数是在基类中声明的虚函数,声明时无函数体,要求继承它的子类必须覆盖该虚函数,带有纯虚函数的类成为抽象类。 抽象类不能实例化,但其派生类可以。
一个纯虚函数: virtual void showInfo(void) = 0;
#include
class B0 //抽象基类B0声明
{
public: //外部接口
virtual void display( )=0;
//纯虚函数成员
};
class B1: public B0 //公有派生
{
public:
void display(){cout<<"B1::display()"<display(); }
void main() //主函数
{ B0 *p; //声明抽象基类指针
B1 b1; //声明派生类对象
D1 d1; //声明派生类对象
p=&b1;
fun(p); //调用派生类B1函数成员
p=&d1;
fun(p); //调用派生类D1函数成员
}
程序的运行结果为:
B1::display()
D1::display()