c++学习笔记 初识类与对象

来源:互联网 发布:ios天气插件数据不跟新 编辑:程序博客网 时间:2024/05/29 07:33

类有点像结构体,但是类包含有方法(函数)

结构体:

struct stu

{

int a;

double b;

};

类:

class Cla

{

int n;

public:

void set(int a){n=a;}

void show(){cout<<b;}

}

输出相比

结构体:

stu s1={10,12.5};

cout<<s1.a<<s1.b;

类:

Cla c1;

c1.set(10);

c1.show();


在类里,数据表示为数据成员,如int n;

而函数则表示为成员函数。

与结构体一样,调用类方法时:c1.show()即可。

类里的成员有着访问控制的划分:

类带有访问控制,比如上面的public就表示以下成员是公有的,可以通过这个类对象(c1)调用这个方法(函数):c1.show();

而c1里面的n是外面不可见的(默认private),只能在类的成员函数里能使用,比如说只有c1的show方法才能看见n;

类的访问控制分为三部分:private、protected、public

class Cla

{

private: //表示成员是私有的,只能被这个对象的保护和公有成员访问

int a;

int b;

int sum;

protected: //表示成员是保护的,只有这个类和派生类的成员才能访问,但是不能通过对象调用

int add(){reurn a+b;}

public: //表示成员是公有的,任何人都可以访问这个成员

void show(){cout<<a<<"+"<<b<<"="<<add();

}

所以,不能直接使用对象访问私有与保护成员:

Cla c1;

c1.a=10; //错误,无法通过对象访问私有对象

cout<<c1.add();//错误,无法通过对象访问保护对象


默认成员是私有的:

class A

{

int a; //当成员没有访问控制时默认是private私有的

public:

void show(){cout<<a;}

}

如果要读取私有数据成员,可以像show一样,定义一个成员函数返回数据:int get()const{return a;}


类定义在头文件,类方法的实现则建议在cpp文件里,比如有这样的一个类:

.h

//头文件定义类与类方法

class Fruit

{

string name;

double heat;

double weight;

protected:

double sum()const;//const修饰符表示该方法不能修改该对象的数据

public:

void set(string n,double h,double w);

void show();

}

.cpp

//cpp文件实现类方法

double Fruit::sum()const

{

reurn heat*weight;

}

void Fruit::set(string n,double h,double w)

{

name=n;

heat=h;

weight=w;

}

void Fruit::show()

{

cout<<"name:"<<name<<"\tenergy:"<<sum();

}


用作用域解析运算符::来指出所属的类,如 double Fuit::show()表示这是一个属于Fuit对象的方法,该方法返回double值。

每个对象都有自己的数据:

Fruit apple;

Fruit peach;

apple.show();

peach.show();

每个对象都调用自己的方法,各不冲突和结构体类似。


类有着特别的函数:构造函数与析构函数

构造函数与析构函数与类名相同

如:Friut类的构造函数为Friut();析构函数为~Fruit();

当使用类定义一个对象时,如:Fruit apple; 这时构造函数将自动调用。

当对象过期时,该对象会自动调用一个特殊的函数:析构函数

定义指针不会调用:Fruit *p;

但是为指针分配地址时会调用:Friut *p=new Fruit("pear",10,20);

构造函数的作用是当对象被创建,自动调用构造函数对对象的一些数据成员进行设置。

每个类都有一个默认构造函数与析构函数,当你没有定义时,c++将自动提供一个没有任何参数不进行任何操作的默认的构造函数:

类名(){//动作};如Fruit(){}

Fruit apple; 

就如同int x;一样。


构造函数在类里声明:

class Fruit

{

....

public:

Fruit(const string str="NULL",double h=0,double w=0);//声明默认构造函数

}

当给构造函数的每个值都设置初值时,该构造函数就是默认构造函数的一种。

当然你可以为默认构造函数提供初始化成员数据的功能:

.h

Fruit();

.cpp

Fruit::Fruit()//说明这个构造函数Fruit是Fruit类的

{

name="NULL";

heat=0.0;

weight=0.0;

}

当类定义了一个构造函数(没有全带默认参数),这必须声明默认构造函数,否则会出错:

class A

{

...

public:

A(int a,int b);//出错

}

原因是,当定义一个类对象时,会自动调用默认构造函数,但是没有定义,所以会出错:

A c1; //出错,没有名为A()的构造函数

所以当需要定义构造函数时,而该构造函数又不是全部有默认值就必须提供默认构造函数:

.h

class Fruit

{

.....

public:

Fruit(){}

Fruit(const string &str,double h,double w);//&str为引用速度比较快,不用调用string复制构造函数,即不用把整个对象复制过去,只需要把地址复制

}

.cpp

Fruit::Fruit(const string &str,double h,double w)

{

name=str;

heat=h;

weight=w;

}

可以定义多个构造函数,应对不同的初始化条件:

比如定义一个Fruit(const char *str,double h,double w)的构造函数应对char指针数组的初始化。


如果构造函数只有参数:

class A

{

int n;

public:

...

}

则下面的语句都可以可以初始化:

A c1=A(10);

A c2(20);

A c3=30;


析构函数在对象过期时自动执行,对对象进行清理操作。

析构函数:~类名();

如:~Fruit();

当该对象类的数据成员没有使用动态内存分配(如new)时,只需要一个声明都不干的析构函数即可.

如:~Fruit(){};


c++有两种调用构造函数的方法:显式调用、隐式调用

显式调用:

Fruit apple=Fruit("apple",10.0,20.0);

隐式调用:

Fruit apple("apple",10.0,20.0);

隐式调用更紧凑,结果与显式调用等价。


this指针:

它的作用很明显:代表当前这个对象的地址

下面演示使用:

比如有一个类:

class Num

{

int a;

public:

Num(int n=0);

Num &max(const Num &n)const;

void show();

}

.cpp //实现

Num::Num(int n)

{

a=n;

}

Num Num::max(const Num &n)const

{

if(a<n.a)

return n;

else

return *this;//这里是返回这个方法所在的对象

}

void Num::show()

{

cout<<a;

}


main.cpp

Num n1(10),n2(5);

Num n=n1.max(n2);

n.show();


其实方法show()也隐式地使用了this:

void Num::show()

{

cout<<this->n;//相当于这样

}

this代表这个方法所属的对象的地址,所以可以通过this指针返回当前对象的地址,一般不会显示的写出this->n这样的表示,而是直接n。


有关类的数组,和普通数组一样,使用[*]来确定数组大小:

Fruit Fruits[5];

前面说过构造函数可以让类对象这样初始化:

Fruit f1("apple",10,20);

也可以:

Fruit f1={"apple",10,20};

所以像也可以像结构体数组一样初始化,前提是这个类有提供相对的构造函数:

Fruit fruits[5]={

{"apple",10,20},

{"pear",10,15},

{“grapes”,10,10},

{"banana",20,30},

{"pomegranate",20,15}

}

他会对应的调用构造函数

又可以:
Fruit fruits[5]={

Fruit(),

Fruit("pear",10,20),

Fruit(""banana")

}

剩余的部分使用默认构造函数。


关于类的作用域:

在类中定义的成员的作用域为整个类,即所有的这个类的方法都可见,但是类外则是根据访问控制控制的。

在类中不可以像外面一样定义常量:

class A

{

const int MAX=10;//没用~

char name[MAX];//无效

....

}

这样是不行的,因为类的声明不会创建对象,所以MAX不存在。

但是可以有这两种方法代替:

使用枚举

class A

{

enum {MAX=10};

char name[MAX];

.....

}

枚举也一样不会创建一个名为MAX的常量,但是它和#define 一样,在编译器遇到它时自动将MAX替换为10。

这里的枚举只是用于创建常量,所以不需要枚举名。

使用static

class A

{

const static int MAX=10;//创建一个静态的常量

}

根据书上说的,在类里使用static修饰符的数据类型与方法是所有该类对象共享的,因此,可以说明一个静态int类记录该类对象的数量:

class Num

{

static int count;

.....

public:

......

}

然后这个静态数据成员需要初始化:

.cpp

int Num::count=0;

在构造函数里++count:

Nu::NUM(int n)

{
++count;

.....

}



                                             
0 0