适合具备 C 语言基础的 C 教程(三)
扫描二维码
随时随地手机看文章
前言
在上一则教程中,着重地阐述了构造函数以及析构函数的相关概念,这也是C
中非常重要的两个概念之一。在今天的教程中,笔者将继续叙述 C
相对于 C
语言来说不同的点,将详细叙述命名空间,静态成员,友元函数以及运算符重载这几个知识点。C 命名空间
命名空间的存在是为了区分不同库的相同的函数名,用一个简单的例子来说明这个问题就是在windows
的文件系统中,不同文件夹下可以有相同名字的文件,相同文件夹下因为这相同文件处在不同的范围内,用 C 说白了也就是处在不同的命名空间中。文件系统的一个结构图:定义命名空间
命名空间的定义使用的是关键字 namespace,后跟命名空间的名称,如下所示:namespace namespace_name{
// 代码声明
}
为了调用带有命名空间的函数或者变量,需要在前面加上命名空间的名称,如下所示:name::code // code 可以是变量或者是函数
例子
下面通过一个例子来说明命名空间的概念,首先,我们具有两个类,一个是 Dog ,一个是 Person,而这个时候,有两个函数具有相同的名字,都要输出不同的信息,这个时候,就有必要使用到命名空间的概念。首先,我们在 dog.h 里面定义一个 dog 类,代码如下所示:#ifndef __DOG_H__
#define __DOG_H__
namespace C{
class Dog{
private:
char *name;
int age;
public:
void setName(char *name);
int setAge(int age);
void printInfo(void);
};
void printVersion(void);
}
#endif
然后,紧接着来看 dog.cpp 里面的内容。代码如下所示:#include "dog.h"
namespace C{
void Dog::setName(char *name)
{
this->name = name;
}
int Dog::setAge(int age)
{
if (age < 0 || age > 20)
{
this->age = 0;
return -1;
}
this->age = age;
return 0;
}
void Dog::printInfo(void)
{
printf("name = %s, age = %d\n",name,age);
}
void printersion(void)
{
printf("Dog v1");
}
}
OK ,看完了 Dog 的代码,我们紧接着来看 Person 的代码,代码如下所示:#ifndef __PERSON_H__
#define __PERSON_H__
namespace A{
class Person{
private:
char *name;
int age;
char *work;
public:
void setName(char *name);
int setAge(int age);
void printInfo(void);
};
void printfVersion(void);
}
#endif
紧接着就是 Person.cpp 的代码,具体的代码如下所示:namespace A {
void Person::setName(char *name)
{
this->name = name;
}
int Person::setAge(int age)
{
if (age < 0 || age > 150)
{
this->age = 0;
return -1;
}
this->age = age;
return 0;
}
void Person::printInfo(void)
{
printf("name = %s, age = %d, work = %s\n", name, age, work);
}
void printVersion(void)
{
printf("Person v1\n");
}
}
上述就是 所定义的两个类,我们紧接着来看 main.cpp 的代码:int main(int argc, char **argv)
{
A::Person per;
per.setName("zhangsan");
per.setAge(16);
per.printInfo();
C::Dog dog;
dog.setName("wangcai");
dog.setAge(1);
dog.printInfo();
A::printVersion();
C::printVersion();
return 0
}
在最后的倒数第二行和倒数第三行,我们可以看到如果这个时候,没有命名空间的存在,那么就完全不能够分辨 printVersion
这个函数,加上了命名空间之后,就能够分辨出来了。静态成员
在上述代码的基础上,我们在主函数定义了如何几个变量,代码如下所示:#include
int main(int argc, char **argv)
{
Person per1;
Person per2;
Person per3;
Person per4;
Person *per5 = new Person[10];
}
那我们要如何知道我们定义几个 Person 对象呢,可以这样去做,我们创建一个 cnt
变量,然后在每个构造函数执行的过程中让 cnt
加一,代码如下所示:#include
#include
#include
class Person
{
private:
int cnt;
char *name;
int age;
char *work;
public:
Person()
{
name = NULL;
work = NULL;
cnt ;
}
Person(char *name)
{
this->name = new char[strlen(name) 1];
strcpy(this->name, name);
this->work = NULL;
cnt ;
}
Person(char *name, int age, char *work = "none")
{
this->name = new char[strlen(name) 1];
strcpy(this->name, name);
this->work = new char[strlen(work) 1];
strcpy(this->work, work);
cnt ;
}
~Person()
{
if (this->name)
{
cout << "name is:" << name << endl;
delete this->name;
}
if (this->work)
{
cout << "work is:" << work << endl;
delete this->work;
}
}
};
但是如果这么写的话存在一个问题,就是我们想要实现的功能是看有几个实例化 Person
对象,那么这个计数量cnt
应该是属于 Person
类的,具体的关系如下图所示:但是上述的代码中,cnt
是属于 Person
的实例化对象的,那要如何做才能使得 cnt
属于 Person
类的实例化对象呢,这个时候,我们需要将 cnt
定义为 static
类的,这样子,cnt
就是属于 Person
类的了,定义的代码如下所示:class Person
{
private:
char *name;
int age;
char *work;
static int cnt;
};
那么我们要如何得到 cnt 的值呢,可以编写一个函数,但是同样的,我们编写的函数要是属于整个 Person
类的,那应该如何去做呢,同样的办法,我们在前面加上 static
,代码如下所示:#include
#include
class Person
{
private:
char *name;
int age;
char *work;
static int cnt;
public:
static int getcount(void)
{
return cnt;
}
};
有了 getcount
函数,我们就可以调用它,然后将其打印出来,方法如下所示:#include
int main(int argc, char *argv)
{
Person per1;
Person per2;
Person *per5 = new Person[10];
count << "person number = " << Person:getcount() << endl;
}
最后,还存在一个问题,因为我们在 cnt
上加了 static
,那么当前的 cnt
就是属于 Person
类的,这样一来,那么就是说 cnt
的值还没有分配空间,那么要如何分配空间呢,我们需要在主函数开始之前对 cnt
进行定义和初始化,代码如下所示:int Person::cnt = 0; /* 定义*/
这样的话,就可以知道 cnt
的值了,下面是运行的结果:这样,就知道了 Person
类的实例化次数。那为什么要把 int Person::cnt = 0
放在 main
函数的最开始呢,这是因为要在 main
所有实例化对象定义之前就要将其初始化完成。友元函数
首先,我们有这样一个需求,需要实现两个类的相加,下面是写出来的代码:#include
#include
#include
using namespace std;
class Point
{
private:
int x;
int y;
public:
Point(){}
Point(int x, int y) : x(x), y(y) {}
void setX(int x)
{
this->x = x;
}
void setY(int y)
{
this->y = y;
}
int getX(void)
{
return x;
}
int getY(void)
{
return y;
}
};
Point add(Point