类与对象

1.  类的定义

类是对具有相同属性和行为的一组对象的抽象与统一描述。是用户自定义的数据类型

●类的定义包括行为和属性两个部分。

● 属性以数据表示,行为通过函数实现。

2。类的表现形式

class 类名   //除class外还有struct,区别是struct所有成员都是公有的。

{

  public:

          公有数据成员和成员函数;

  protected:

          保护数据成员和成员函数;

  private:

          私有数据成员和成员函数;

};   //冒号不能省略。

  各成员函数的实现


class Student 	     //定义学生类Student
{
public: 		     //声明类成员 
	    void Getinfo(string pname, string pid
            ,char Sex, int a,double s);
	    void modify(float s);
	    void display();
private: 
	    string name;
      stringid;
      char sex;
	    int age;
	    double score;
}; 	//类定义以分号结束 

注意:1. 类与结构体相比是具有封装性的,是指没有明确指定类成员的访问权限时,C++结构体的成员是公有的,而类的成员是私有的。

      2. 类的成员可以是其他类的对象,结构,数组,类等,但不能以类自身的对象作为本类的成员。

 

class student
{  
   char name[10];
   date birthday;
   long code;
   char *address;
   char phone[20];
   //····
};

3.类的访问控制

访问属性:
      ● Public      公有成员,类的外部接口,在类内外可以访问
      ● Protected   保护成员,仅允许本类成员函数及派生类成员函数访问
      ● Private      私有成员,仅允许本类成员访问
注意:各种不同访问性质的成员说明段在雷丁中没有顺序规定,可以重复出现,public和private也是没有先后的,一般为了方便与接口,把公有成员放在开始。

4.成员函数

定义:

类的成员函数是实现类的行为属性一般将成员函数声明为函数原型,在类外具体实成员函数

形式表现:  

返回值类型  类名::成员函数名(参数表)

{

          函数体

}

class Point	
{
public:	 
	float GetPointx();
	float GetPointy();
	void InitPoint(float PointA_x, float PointA_y); 
        private:
	 float P1_x,P1_y;
void Point::InitPoint(float PointA_x, float PointA_y) 
{
	P1_x=PointA_x;
	P1_y=PointA_y;
}
}
注意:简单的成员函数实现可以在类中定义,称为内联函数。
         内联函数作用:减少频繁调用小子程序的运行的时间开销。
         内联函数声明:  inline  函数原型。
         内联函数仅在函数原型作一次声明。适用于只有1 ~ 5行的小函数。不能含有复杂结构控制语句 ,不能递归调用。
//····
public:
     void setdate(int y,intm,int d)
     { year=y;
       month=m;
       day=d;
     }
5.对象
    对象是类的实例或实体。类与对象的关系,如同C++基本数据类型和该类型的变量之间的关系。
格式:类名  对象名1,对象名2,…,对象名n
注意: 必须在定义了类之后,才可以定义类的对象。
6.成员访问

       ●圆点访问形式:对象名.公有成员
       ●指针访问形式  :对象指针变量名—>公有成员

#include<iostream.h>
class ptr_access
{public:
void setvalue(float a, float b) { x=a; y=b; }
float Getx() {return x;}
float Gety() {return y;}
void print() { cout<<"x="<<x<<endl; cout<<"y="<<y<<endl; }
private: //私有数据成员
float x,y;};
int main()
{
float a1,a2;
ptr_access *ptr=new ptr_access;
ptr->setvalue(2,8); ptr->print();
a1=(*ptr).Getx(); return 0;
}

7.成员函数重载
函数重载:函数名相同,但参数不相同(类型不同,或者个数不同)的一组函数。 编译器根据不同参数的类型和个数产生调用匹配。 函数重载用于处理不同数据类型的类似任务。

1.构造函数和析构函数

① .构造函数定义:构造函数是用于创建对象的特殊成员函数当创建对象时,系统自动调用构造函数

 构造函数的作用是: 为对象分配空间;对数据成员赋初值;请求其他资源

② 析构函数定义:析构函数是用于取消对象的成员函数当一个对象作用域结束时,系统自动调用析构函数

 析构函数的作用是进行对象消亡时的清理工作

 

③ 注意:没有用户定义的构造函数时,系统提供缺省版本的构造函数。构造函数名与类名相同。构造函数可以重载。构造函数可以有任意类型的参数,但没有返回类型。构造函数在建立对象时自动调用。没有用户定义析构函数时,系统提供缺省版本的析构函数。 析构函数没有参数,也没有返回类型。

④ 构造函数和析构函数的原型:

   类名::类名(参数表);

  类名::~类名();

Date::Date(int y,int m,int d)

{ year=y; month=m; day=d; }

Date::~Date()

{  cout<<date object initializad/n;}

注意:构造函数和析构函数不应定义在私有部分。

⑤ 构造函数组成分为带参构造函数和默认构造函数;如果类中没有定义构造函数,系统将自动生成一个默认形式的构造函数,用于创建对象,默认构造函数是一个空函数。

class Date {

    public:

    Date();     /

    Date(int y,int m,int d);

        Void Set Date(int m,int n,int t);        

    void showDate();

    private:

            int year, month, day;

    };

Date::Date()    // 构造函数的实现

{  year=0; month=0; day=0; }

Date::Date(int y,int m,int d)

{ year=y; month=m; day=d; }

Void Date::setDate(int m,int n,int t)

{year=m;   day=t;  month=n;}

注意;Date::Date()和Date::SetDate()的区别是SetDate可以多次重置数据成员的值,构造函数仅用于创建对像和数据初始化。

⑥ 构造函数创建对象的两种方法:

v 利用构造函数直接创建对象:date.date(1998,4,28);

v 利用构造函数创建对象时,通过指针和new来实现。 类名 *指针变量 = new 类名[(实参表)];Date *date1=new Date(1998,4,28);构造函数的初始化列表

v 使用构造函数的函数体进行初始化 Date(int dd, int mm, int yy)

{

d=dd;

m=mm;

y=yy;

}

 

v .使用构造函数的初始化列表进行初始化 

funname(参数列表):成员1(形参名1),成员名2(形参名2),成员名n(形参名n)

{  函数体,可以是空函数体  }

Date(int dd, int mm, int yy):d(dd),m(mm),y(yy)

{ }

 

注意:必须使用参数初始化列表对数据成员进行初始化的情况:

     数据成员为常量。数据成员为引用类型。数据成员为没有无参构造函数的类的对象。

public:

A(int i):x(i),rx(x),pi(3.14)

{}

void display()

{cout<<"x="<<x<<"rx="<<rx<<"pi="<<pi<<endl;}

private:

int x,℞

const float pi;

类成员的初始化的顺序:

按照数据成员在类中的声明顺序进行初始化,与初始化成员列表中出现的顺序无关

 

#include <iostream>
using namespace std;
class CMyClass{
public:
	CMyClass(int x, int y):m_y(x),m_x(m_y)   //与初始化列表顺序无关,先赋值的是 x后y
	{
		cout<<"m_x="<<m_x<<endl;
		cout<<"m_y="<<m_y<<endl;
	}
private:
	int m_x,m_y;      //与赋值顺序有关
};
int main()
{
	CMyClass mc(15,10);
	return 0;
}

2. 构造函数的重载

构造函数可以具有默认参数。定义构造参数时,注意调用时可能产生的二义性

class Box
{public:
Box();
Box(int ,int , int);
private:
int height,width, length;};
Box::Box(){ height=10; width=10; length=10;}
Box::Box(int h, int w,int l):height(h),width(w),length(l){}
int main()
{ Box box1;
 cout<<"The volume is "<<box1.volume(); 
Box box2(12,30,25);
 cout<<"The volume is "<<box2.volume();
 return 0;
}

构造函数一般被定义为公有成员。一般情况下,可以不定义析构函数但如果类的数据成员中包含指针变量是从堆上进行存储空间分配的话,需要在析构函数中进行存储空间的回收
3.this 指针用来指向不同的对象。
引用this的三种情况:
(1)在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用 return *this,返回本对象的地址时,return this。
(2)当参数与成员变量名相同时,如this->x = x,不能写成x = x。
(3)避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针。
class Person{
public:
	Person(string n, int a)	{
		name = n;    //这里的 name 等价于this->name
		age = a;      //这里的 age 等价于this->age
	}
	int get_age(void) const{  return age;  }
	Person& add_age(int i)	{age += i;    	return *this;  	}
private:

注意:当参数与成员变量名相同时void set_x(int x) { this->x = x; }
4.复制构造函数
复制构造函数用一个已有同类对象创建新对象进行数据初始化。
形式:类名 :: 类名(const  类名  &  引用名  ,  …)
注意:
 复制构造函数名与类名相同,并且也没有返回值类型。复制构造函数可写在类中,也可以写在类外。复制构造函数要求有一个类类型的引用参数。 如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数。

public:
	Box(int =10, int =10, int =10);
	Box(const Box & b)  //形成一个类b,然后将b复制成box
	{height=2*b.height;	width=2*b.width;length=2*b.length;}
	int volume();
private:
	int length, height, width;
};int main(){
 Box box1(1,2,3),box2(box1),box3=box2;}    //两种复制形式


 5.复制构造函数的调用
  •          声明语句中用类的一个已知对象初始化该类的另一个对象时。
  • 当对象作为一个函数实参传递给函数的形参时,需要将实参对象去初始化形参对象时,需要调用复制构造函数。
  • 当对象是函数的返回值时,由于需要生成一个临时对象作为函数返回结果,系统需要将临时对象的值初始化另一个对象,需要调用复制构造函数。

6.浅复制和深复制

 浅复制:
●在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式。
即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容。默认复制构造函数所进行的是简单数据复制,即浅复制

 深复制:
●通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制。 
深复制构造函数必须显式定义。
类的其他成员
1.常数据成员
常数据成员是指数据成员在实例化被初始化后,其值不能改变。
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数
注意:
如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。
由构造函数直接常量初始化
 public :
       int k;
       const int M;
       Mclass() : M(5) { }
       void testFun()
        { //M++;   //不能在成员函数中修改常数据成员
           k++;  //可以修改一般数据成员
            k++;
        }
用带参数的构造函数初始化常数据成员

public: Student (int y,int m,int d, int num=0, sring name="no name"); void PrintStudent()const; //常成员函数 private: const int code; //常数据成员 string name; Date birthday; //结构数据成员 };
Student::Student( int y, int m, int d, int num, string name ) : code( num )

2常对象
如果在说明对象时用const修饰,则被说明的对象为常对象。
    常对象的说明形式如下:
      类名 const 对象名[(参数表)];
  或者
      const  类名 对象名[(参数表)];
3.常成员函数
       类型说明符 函数名(参数表) const;
      const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
     常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)
  
class  Simple
{   int  x, y ;
  public :
     void setXY ( int a, int b) { x = a ;  y = b ; }
     void printXY() { cout << x << "," << y << endl ; } 
     void  constFun ( ) const
         { x ++ ; y ++ ; }//非法
};

4.静态成员
类成员冠以static声明时,称为静态成员。  静态数据成员为同类对象共享。静态成员函数与静态数据成员协同操作。 
静态成员不属于某一个单独的对象,而是为类的所有对象所共有。它的作用不是为了对象之间的沟通,而是为了能处理静态数据成员: 保证在不依赖于某个对象的情况下,访问静态数据成员
class A
{
   int n;
 static int s;
};
注意:
对于类的普通数据成员,每一个对象都各自拥有一个副本。(分配不同的存储空间)。对于静态数据成员,每个类只拥有一个副本
5.在类外进行静态数据成员的声明
类型 类名::静态数据成员[=初始化值];   不能在成员初始化列表中进行初始化。如果未进行初始化,则编译器自动赋初值(默认值是0)。初始化时不能使用访问权限
静态函数仅可以访问静态成员,或是静态成员函数或是静态数据成员。

静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
1.友元函数
如果在本类(类A)以外的其他地方定义了一个函数(函数B),这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数,在类体中用friend对其(函数B)进行声明,此函数就称为本类(类A)的友元函数。
友元函数(函数B)可以访问这个类(类A)中的私有成员
class  A
   { private:
          int  i ;
          friend void FriendFun(A * , int) ;
      public:
         void MemberFun(int) ;
   } ;
    …
void FriendFun( A * ptr , int x  )
     { ptr -> i = x ; }
2.类的包含

类的包含是程序设计中一种软件重用技术。即定义一个新的类时,通过编译器把另一个类 “抄”进来。
 当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ;
3.初始化:
出现成员对象时,该类的构造函数要包含对象成员的初始化。如果构造函数的成员初始化列表没有对成员对象初始化时,则使用成员对象的无参(缺省)构造函数。

建立一个类的对象时,要先执行成员对象自己的构造函数,再执行当前类的构造函数
class B
{ public:
     B( int x, int y ) : aa(x)  { b = y ; }
     void out() { cout<<"aa = "<<aa.a<<endl<<"b = "<<b<<endl ; }
  private:
     int b ;
     A aa ; 
} ;
4.对象数组

所谓对象数组是指每一数组元素都是对象的数组。 类名 数组名[下标表达式];

对象数组初始化
当对象数组所属的类中包含带参的构造函数,可用初始化列表完成对象数组的初始化。

int main(){
	Point p1[4];
	Point p2[4]={5,6,7,8};
Point  p3[4]={Point(9,10),Point(11,12),Point(13,14),Point(15,16)};
	Point p4[4]={Point(17,18),Point(10,20)};
	Point p5[2][2]={21,22,Point(23,24)};
	}

  当对象数组所属的类中包含无参的构造函数,也可以先定义,再给每个数组元素赋值
int main(){
 Point p1[4];
             p1[0]=Point(1,1);
}
个人心得:
学习类了以后,我学得了一个新思想,可以从整体想问题,而且与实际联系也多了,觉得很有趣,解决问题也更方便。但是在类中的学习中,需求与代码的联系不好,有时不知道如何把一个要求转化成代码,这个以后要多加注意,再者就是以后多注意向自己的思想靠拢,不要过于模仿。在理解概念的基础上进行练习,一步一步了解并熟悉类。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值