C语言与C++均是两门非常高深及优秀的语言,二者具有类似的地方,但是相较与他们之间的区别来说呢,也就不那么重要了,C++在C语言的基础上增加了面向对象的编程模式。
面向对象:用非常接近实际领域术语的方法把系统构造成“现实世界”的对象。
一、C++类的定义
类的关键字:class
C++的主体是以类和对象构成的,利用类来将“现实世界”中的各个对象给抽象出来。由class关键字以及类的名称以及类中的成员来定义。类中可以没有成员,也可以有多个成员 。但是没有成员时也会占用一定的空间。
二、类中的内容
C++中的类主要包含以下几个方面:
1、成员变量:成员变量是指一个类的固定的属性。
2、成员方法:成员方法可以理解为一个类中固有属性的行为方法。
3、访问权限:对类中的成员变量及成员方法的访问权限,分为public,private,protected三种权限。
1) public:即公有权限,在此权限的作用域下,外界可以访问该类中的成员变量及成员方法。
2) private:即私有权限,在此权限的作用域下,外界不可以访问该类中的成员变量和成员方法。
3) protected:即保护权限,外界无法直接访问这个控制级别的成员,但是子类(派生类)可以获得访问父类的成员变量和成员方法的能力。
4、类的作用域:每个类都定义了自己的作用域和唯一的类型。
类的作用域包括:类的内部(花括号之内), 定义在类外部的成员函数。
在类外进行对类的成员方法进行实现时,需要加上该成员函数的作用域,即类名加上::加上函数名。在类外实现的函数需要在类内进行声明。成员函数的返回类型不一定在类作用域中。
例:
class People
{
public:
//在类内实现函数
void eat()
{
cout << "eat eat eat" << endl;
}
//在类外实现的函数需要在类内声明
void walk();
private:
char* _name;
int _id;
char* _height;
char* _weigh;
};
//在类外实现成员方法
void People::walk()
{
cout << "walk walk walk" << endl;
}
例如上图代码中People就是一个类,People类中的_name,_id,_height,_weight即是类中的成员变量,eat(),walk()是类中的成员方法,piblic,private是访问权限,如果我们在主函数中是不允许去访问private作用域下的成员变量的。而在public作用域下的成员方法是可以被外界调用的。
三、类的四大函数
1、构造函数:构造函数是一个特殊的、与类同名的成员函数,用于对该类的各个成员进行初始化。如果没有在类中实现类的构造函数,系统会自动给一个构造函数,但是这个构造函数什么都不做。
2、析构函数:析构函数是对利用类来定义出的对象进行分解及所占用堆上的内存进行释放的函数,在程序结束后,系统会自动去调用析构函数。也是很特殊的一个函数,与类名相同,但需要在函数名前加上“~”,例如:~People(),与构造函数类似,假如没有给出析构函数,系统也会默认给一个析构函数,但也是什么也不做。
注意:防止内存泄露
3、拷贝构造函数:拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其形参必须是引用,但并不限制为const,一般普遍的会加上const限制。
注意:防止浅拷贝
在C++中,下面三种对象需要调用拷贝构造函数:
1) 一个对象作为函数参数,以值传递的方式传入函数;
2) 一个对象作为函数返回值,以值传递的方式从函数返回;
3) 一个对象用于给另外一个对象进行初始化(常称为赋值初始化);
4、等号运算符的重载函数:当我们需要用到等号来对一个对象进行复制时,就需要用到我们的等号运算符重载函数。当我们没有自己设计等号运算符的重载函数,编译器会自动生成一个浅拷贝的赋值运算符的重载函数。
注意:防止自赋值 防止内存泄漏 防止浅拷贝
例如:
class Person
{
private:
char _name[20];
char *_name;
bool _sex;
int _age;
public:
//构造函数(有参数)
Person(const char *name, bool sex, int age)
{
cout << "Person(const char *name, bool sex, int age)" << endl;
_name = new char[strlen(name) + 1];
strcpy_s(_name, strlen(name) + 1, name);
_sex = sex;
_age = age;
}
//构造函数(无参数)
Person()
{
_name = NULL;
cout << "Person()" << endl;
}
//拷贝构造函数
Person(const Person& src)
{
cout << "Person(Person& src)" << endl;
//防止浅拷贝
_name = new char[strlen(src._name) + 1];
strcpy_s(_name, strlen(src._name) + 1, src._name);
_sex = src._sex;
_age = src._age;
}
//等号运算符的重载函数
Person& operator=(const Person& src)
{
cout << "=====" << endl;
//防止自赋值
if (this == &src)
{
return *this;
}
//防止内存泄漏
if (NULL != _name)
delete[]_name;
//防止浅拷贝
_name = new char[strlen(src._name) + 1];
strcpy_s(_name, strlen(src._name) + 1, src._name);
_sex = src._sex;
_age = src._age;
return *this;
}
//析构函数
~Person()
{
cout << "~Person()" << endl;
delete []_name;
_name = NULL;
}
void eat(/*Person * const this*/)
{
cout << this->_name << "::::eat" << endl;
}
};
四、实例化对象
类既然已经被我们抽象的定义出来了,那么类是如何去使用的,这就得用到对象了。
对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。
1、对象的实例化:通过类中的构造函数来实例化出一个拥有类中的成员变量(固有属性)以及成员方法的调用。
2、类成员方法的调用:通过实例化出来的对象进行对类中所实现的成员方法进行调用。用对象加上’.’加上函数名进行调用。
例:
int main()
{
//使用有参数的构造函数实例化对象
Person person1("zhangsan", true, 23);
//成员方法的调用
person1.eat();
//使用无参数的构造函数实例化对象
Person person2;
//拷贝构造出一个对象
Person person3 = person1;
//利用等号运算符重载函数给一个对象赋值
Person person4;
person4 = person3;
return 0;
}
3、this指针:一个隐藏起来的指针,指向对象的指针,在成员方法调用的时候默认传入一个this指针,在成员方法声明/定义的地方,默认加上this指针参数,在成员方法中使用成员变量的地方加上this->。
五、友元
友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。
友元函数:友元函数是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。
友元类:友元除了函数以外,还可以是类,即一个类可以作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
例如我们在一个类中定义了一个私有成员变量,不想让外界访问,但是却又希望个别的函数或是类对我们的所定义的私有成员变量进行访问,这个时候就可以利用友元函数和友元类进行明确的指定某个函数或某个类可以访问这些私有变量。
class List
{
private:
Node *_head;
class Node
{
public:
Node()
{
_next = NULL;
}
~Node()
{
_next = NULL;
}
private:
ElemType _data;
Node * _next;
//让List变为友元类
friend class List;
};
public:
List()
{
_head = NULL;
}
~List()
{
while (_head != NULL)
{
DeleteElemOfList();
}
}
Node *BuyNode(ElemType val)
{
Node *s = new Node();
s->_data = val;
s->_next = NULL;
return s;
}
void InsertElemToList(ElemType val)
{
Node *s = BuyNode(val);
if (_head == NULL)
{
_head = s;
}
else
{
Node *p = _head;
while (p->_next != NULL)
{
p = p->_next;
}
p->_next = s;
}
}
void DeleteElemOfList()
{
Node *p = _head;
if (_head->_next == NULL)
{
delete p;
_head = NULL;
}
else
{
while (p->_next->_next != NULL)
{
p = p->_next;
}
Node *q = p->_next;
p->_next = NULL;
delete q;
}
}
void ShowList()
{
Node *p = _head;
while (p != NULL)
{
cout << p->_data << " " ;
p = p->_next;
}
cout << endl;
}
};
我们的单链表中有Node这样的类,但是Node中的next指针域和data数据域是私有变量,不允许外界访问,但是List类却需要对Node类中的这些私有成员进行访问,所以给加入了友元类就可以成功的进行访问。