C++学习:类与对象

参考书籍:《c++程序设计》张军编著

1.面向对象

类 就是描述一类问题的共同属性和行为。(共同的,是吧,用个类,就方便使用。属性,一般就是参数咯,行为,一般就是函数噻),他是抽象的,就像“时钟”,只是一种概念,不占存储空间,在定义类时,不能初始化。

对象呢,就是类 实例化的一种实体,比如我面前这个时钟(参数被赋值,这里多大什么颜色的时钟)

比如,我建立一个类:

class people

{public:

void setAge(int ageInput)

{

age=ageInput;

}

private:

{

int age;   //一般把属性,数据藏起来,你外人没事别把他搞坏了。函数你随便调用问题不大

}

}

这就建立了一个叫people类,属性:年龄age;行为:设置年龄;

怎么实例化呢?
className  objectName

比如:people Zhang;实例化了一个叫张三的人。

这样我们就可以叫Zhang的人了。

Zhang.setAge(12)  //设置Zhang的年龄12

cout<<Zhang.age<<endl 输出Zhang的年龄;

有了这个类people,我们就可以玩无数个对象了噻,这就是类的好处。

来,我们看下书上的一个简单实例:

#include  <iostream>
using namespace std;
class Clock     //类命名一般首字母大写
{ 
private:
    int hour,minute,second;
public:
    void setTime(int h, int m, int s)  //注意,对函数的命名,一般采用驼峰形状,第一个单词小写,后面的首字母大写;
    void showTime(); //声明函数,然后在后面定义
}
void Clock::showTime()
{
    cout<<hour<<":"<<minute<<":"<<second<<endl;
}
void Clock::setTime(int h,int m,int s)
{
     hour=h;
    minute=m;
    second=s;
}                   //在类外面定义函数的格式 返回值数据类型 类名::函数名;

void main()  //主函数
{
    Clock c1;//实例化时钟对象c1;
    c1.setTime(12,12,12); //调用public的函数
    c1.showTime();
}
//运行结果为
//12:12:12

 

 

2.内联函数与重载函数

内联函数是为了加快运算速度,重载函数是因为太懒,不想给功能相近的函数取两个名字,所以就让他们使用同一函数名(此之谓重也)

内联函数定义:执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还需将返回值放入寄存器中),然后跳回到地址被保存的指令处。

内联函数提供了另一种选择。编译器将使用相应的函数代码替换函数调用。

内联函数的好处:内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。

内联函数的使用:在函数声明前加上关键字inline; 在函数定义前加上关键字inline。

 

重载函数

两个重载函数必须在下列一个或两个方面有所区别:

1、函数的参数个数不同。

2、函数的参数类型不同或者参数类型顺序不同,

C++的这种编程机制给编程者极大的方便,不需要为功能相似、参数不同的函数选用不同的函数名,也增强了程序的可读性。

 

3.类成员访问权限

类里默认是私有private,结构体默认是public。

权限还有另外一种类型,叫做:protected。前面我们也有提,

谁想到这样设置数据的呢?

我们回到现实生活中,

一个类,比如时钟 这个类,

他的参数可能有齿轮比,齿轮数,分,时,秒,行为:有时钟设置,时钟显示,齿轮转动的位置读取;

虽然参数很多,但是我们在程序里,关心的没有内部结构那块,我们只关心:分,时,秒,时钟设置,时钟显示,

就以这些参数与函数定义了结构体,并让分,时,秒praivate; 函数 public。这样保护了参数安全,又可以调用。

以我们前面的例子,你不能在main函数里,写c1.minute=1,这样会失败的。

public: 能被类成员函数、子类函数、友元访问,也能被类的对象访问。 
private: 只能被类成员函数及友元访问,不能被其他任何访问,本身的类对象也不行。即c1.minute不行。 
protected: 只能被类成员函数、子类函数及友元访问,不能被其他任何访问,本身的类对象也不行。

从父类A建立子类B

class B : public A

{   }

子类继承基(父)类里面public和protected中的所有变量和函数。

 

4.构造函数与析构函数

构造函数的作用?与普通函数的区别?

构造函数主要用于解决class对象的数据成员初始化问题。

如果一个类是完全public的

class Clock
{
public:
    int hour, minute, second;
};
Clock c1={12,0,0}

这样就完成了初始化,然而许多class的数据成员是private的,就需要利用构造函数进行初始化;

构造函数的性质:

1. 名字与类名相同;

2.没有返回类型,void也没有,不返回任何值

3. 构造函数由系统自动调用,不用用户调用;

4. 一般来说,构造函数的访问权限为public, 特殊情况下也可以为其他访问权限;

5.构造函数具有成员函数的所有属性,包括 可以重载;可以设置默认形参默认值;

【注意,因为重载与可以设置默认形参值,可能造成二义性】

class Clock
{
public:
    Clock();
    Clock(int newH, int newM, int newS);
private:
    int hour,minute,second;
};
Clock::Clock()     //构造函数1
{
    hour=minute=second=0;
}
Clock::Clock(int newH, int newM, int newS)//构造函数2
//Clock::Clock(int newH=0, int newM=0, int newS=0)//构造函数2,可以设置默认值
{
    hour=newH;
    minute=newM;
    second=newS;
}
Clock c1; //c1对象调用构造函数1
Clock c2(12,0,0);  //c2对象调用构造函数2
//这里利用了其重载特征,所以可以写两个构造函数,根据输入的参数情况,自动识别并初始化

如上,在有默认值的时候,你写Clock c1; 程序就无法识别是哪一个构造函数了,从而造成了二义性。

#include <iostream>
using namespace std;
class Clock
{
public:
	Clock();
	Clock(int newH, int newM, int newS);
	void showTime()
	{
		cout << hour << ":" << endl;
	};
private:
	int hour, minute, second;
};
Clock::Clock()     //构造函数1
{
	hour = minute = second = 0;
}
Clock::Clock(int newH, int newM, int newS)//构造函数2
//Clock::Clock(int newH=0, int newM=0, int newS=0)//构造函数2,可以设置默认值
{
	hour = newH;
	minute = newM;
	second = newS;
}
void main()
{
	Clock c1; //c1对象调用构造函数1
	Clock c2(12, 0, 0);  //c2对象调用构造函数2
	//这里利用了其重载特征,所以可以写两个构造函数,根据输入的参数情况,自动识别并初始化
	Clock c3(c2);
	c3.showTime();
	system("pause");
};

当你想复制其中的构造函数初始化,直接用  Clock c3(c2)就可以了。因为其c++内部有定义这样一个复制构造函数的形式的。

class Clock
{
public:
    Clock();
    Clock(Clock &c)
.....略去,同上;

}
Clock::Clock()
{
hour=minute=second=0;
}

Clock::Clock(Clock &c)
{
    hour=c.hour;
    minute=c.minute;
    second=c.second;
}   //意思就是说这个复制构造函数不写也可以

下一步,就来到了和构造函数(Constructor)对应的析构函数(Destructor)

不使用new创建对象时,对象的内存空间是在栈中的,其作用范围只是在函数内部,函数执行完成后就会调用析构函数,删除该对象。[参考博文:https://www.cnblogs.com/zhengfa-af/p/8109958.html]

使用new创建对象是创建在堆中的,必须要程序员手动的去管理该对象的内存空间。

构造函数的性质,除了一般成员函数的性质外,还有:

1. 名字必须与类名相同,前面加“~”构成

2. 没有返回类型,包括void,不返回任何值

3. 系统自动调用,不需用户调用;

4. 访问权限为:public

5. 没有形参,不接受任何参数,因此不能重载。

#include <iostream>
using namespace std;
class Clock
{
public:
	Clock();
	Clock(int newH, int newM, int newS);
	~Clock();
	void showTime()
	{
		cout << hour << ":" << endl;
	};
private:
	int hour, minute, second;
};
Clock::Clock()     //构造函数1
{
	hour = minute = second = 0;
}
Clock::Clock(int newH, int newM, int newS)//构造函数2
//Clock::Clock(int newH=0, int newM=0, int newS=0)//构造函数2,可以设置默认值
{
	hour = newH;
	minute = newM;
	second = newS;
}
Clock::~Clock()
{
	cout << "Destructor is called" << endl;
}

int main()
{
	{
	Clock c1; //c1对象调用构造函数1
	Clock c2(12, 0, 0);  //c2对象调用构造函数2
	//这里利用了其重载特征,所以可以写两个构造函数,根据输入的参数情况,自动识别并初始化
	Clock c3(c2);
	c3.showTime();
	}               //这里为什么要加入大括号呢?因为这样大括号之后,就会删除c1等对象,删除对象之前就会执行析构函数,我们就可以看到析构函数的效果,输出。若没有大括号,sytem("pause")在那,没执行完,是不会执行析构的。
	system("pause");
	return 0;
};

C++学习:类与对象

 

C++学习:类与对象

大括号限制作用域。 在大括号内声明的局部变量其作用域自变量声明开始,到大括号之后终结。

好了,本来c++本来自己也会删除这些对象的,那么析构函数我们拿来有什么用呢?

那么就要利用析构函数的一条重要性质了:类的析构函数在对象被删除之前自动调用。 

应用:因此,可以把一些程序的结束清理性工作放在析构函数里(比如,软件结束时,数据库的关闭,服务器的断开等)

关于程序的运行顺序,我们一般认为是从main()开始

C++学习:类与对象

 可以看出,最先执行的,其实是main函数外的静态区初始化,全局变量。