类的定义:
类,最初步的说,其实就是对C语言中结构体的拓展。因为c++有了类,才使c++面向的是对象,也可以说是C语言和C++在明显的区别;在类中,我们可以自定义变量,自定义函数。并且,在类中,在类中,定义的变量默认的权限都是私有private的,即在类中,若你不声明一下变量或者函数为公共public的,编译器就会认为你这个是私有private的,私有的类型在类外无法对其进行访问,所以,想像C语言中对它进行赋值、修改之类的都会出错。在类中,有六大基本隐含函数,还有友元等函数的拓展。
class student //这个中省略了类中的其他函数,只是为了方便解释私有和公共
{ //这就是一种默认情况的,没有声明,所有类中变量都是私有
char a;
int c;
double c;
};
class Student //Student这个类中定义的变量在public的关键字下,所有一切都是公共的,即在类外可以正常访问
{
public:
char d;
int e;
double f;
};
一半情况下,我们把类中的所有成员变量都设置成private型的,而把类中的成员函数都设置成public型,假入我们要在函数外更改类的成员变量时,我们在public下定义一个获取成员变量的函数,这样,我们既可以在类外更改相应的值,又保证了类的封装特性。
类的六大成员函数分别是:构造函数,拷贝构造函数,析构函数,运算符重载,取地址符重载,const修饰的取地址符重载。
构造函数:
构造函数的函数名与类名相同;
没有返回值;
有初始化列表(可以不用);
新对象被创建时,编译器自动调用,且在对象的生命周期内仅被调用一次;
构造函数可以重载,实参决定到底调用哪个构造函数;
如果没有显式定义,编译器会自动生成一个默认的最简单构造函数并调用;
无惨构造函数和带有缺省的构造函数都是构造函数,但缺省构造函数只有一个。
拷贝构造函数
只有单参;
该形参是对本类类型对象的引用;
创建对象时使用已存在的同类对象来进行初始化;
编译器自动调用;
没有返回值;
析构函数:
析构函数是释放空间的;
析构函数没有参数;
没有返回值;
运算符重载:
在类中,如果要使用对于正常变量的“+”、“-”、“*”、“/”...时,无法直接使用,这时,我们就需要对运算符进行重载,以便可以对类的对象进行预期的加减乘除等一系列操作。
运算符重载的关键字为“operator”,在operator前加上返回值类型,operator后直接加上需要重载的符号,例如:
student operator+(const student& s)
{
student S;
S.a = a + s.a;
return S;
}
这可以继续穿插一个“this指针”的问题,this指针是编译器自动产生的,存在当前的类中,this指针的指向就是当前对象,在构造函数、析构函数、拷贝构造函数中虽然无参,或者之后一个参数,但是总有一个隐含的参数,即this指针,之前说的几个函数的参数里面都可以加上一个: student* this,student是我定义的类名。你也可以定义成teacher、worker...
地址符重载
取地址运算符其实在不重载时也可以取当前对象的地址,如下面的一段代码:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class student
{
public:
student(int a = 1, int b = 2, int c = 3)
: _a(a)
, _b(b)
, _c(c)
{ }
student(const student& s)
{
_a = s._a;
_b = s._b;
_c = s._c;
}
private:
int _a;
int _b;
int _c;
};
int main()
{
student s1;
cout << &s1 << endl;
system("pause");
return 0;
}
它输出的是:
但是,我们现在再写一个重载的取地址函数
student* operator&()
{
return this;
}
再看看结果:
虽然二者都可以正常输出地址, 但我们很明显的发现,二者的地址并不想通过,说明没有重载的取地址符还是在一定程度上并不适用于对象。
赋值运算符的重载:
student& operator=(const student& s) // 默认的有this指针
{
_a = s._a;
_b = s._b;
_c = s._c;
return *this; // 因为this是一个指针,而返回值是一个类的对象的引用
} // 所以返回this的解引用
main函数中的简单逻辑
int main()
{
student s1;
student s2(10, 20, 30);
s1 = s2;
cout << s1 << endl;
cout << s2 << endl;
system("pause");
return 0;
}
但是我们在使用cout打印对象时,还要对"<<"进行重载,使之符合类的输出规则
friend ostream& operator<< (ostream &os, student&s); //此部分要在类内声明
ostream& operator<< (ostream &os, student&s) //函数的定义部分要放在类外和main函数外
{
os << s._a << " " << s._b << " " << s._c;
return os;
}
friend是一个关键字,表明在friend后面声明的函数是一个友元函数,可以调用该函数的私有成员变量,使问题变得很简单,但是破坏了类的封装特性。
总之,现在我们就得到了赋值运算符重载过后上面main函数中的逻辑的结果
const修饰的取地址符重载
const Date * operator& () const
{
return this;
}
这个const修饰过的取地址符重载的好处就在于将当前对象的this指针的权限更改为const student* const this,无法更改this的指向和他所指的值。
const的作用
const的作用很大,类中的函数基本都有一个默认的参数--this指针,而const修饰的就是this指针,没有const修饰的this指针的形式形如 student *const this,const修饰的this指针形如const student* const this,即修饰过后的this指针不仅无法更改指向,也不能更改this指向的值。
不能给静态成员函数使用const修饰;
非成员函数不允许用从const修饰;
一半在表示函数参数时,将&和const一起使用;
一般const的使用为:
student& GetNum(const student& s)const // 即在函数名称的后面直接加上const,这样就可以修饰this指针了
在这个函数中,this指向的值不可被更改,并且这个函数中也不能调用不含this指针修饰的函数,因为嵌套的函数没有const修饰,即表明this指向的值可被修改,与嘴外层矛盾。但不含const修饰的函数包含的有const修饰的函数时可以正确运行。
错误示例:
student& GetNum(const student& s1)const
{
student& SetNum(const student& s2)
{
...;
}
}
正确示例:
student& SetNum(const student& s2)
{
student& GetNum(const student& s1)const
{
...;
}
}
static的用法和作用:
static的作用在C语言中就是修饰成静态变量或者静态函数,静态变量就是在第一次调用这个变量时进行初始化,以后都使用这个值的上一次的旧值,一半在循环中会搅乱我们的思维。就像这样:
void fun()
{
int i = 0;
static int a = 0;
int b = 0;
printf("a=%d,b=%d\n", a, b);
a += 1;
b += 1;
}
int main()
{
int i = 0;
for (; i < 10; i++)
{
fun();
}
system("pause");
return 0;
}
正确的输出结果位:
而static在修饰函数时,表明此函数只能在本文件中调用,有效保证了函数实现的保密性。
static在C++的类中也表示该变量是一个静态变量,这个静态变量可以直接用类名加限定符访问,表示类中的成员的值,而不是表示当前对象中该变量的值。且该变量在类外要重新定义,如
static int count; //类内的定义
int student::count ; //类外的定义
对于static修饰的成员函数,则表示在当前函数内不存在this指针,所以一般情况下此类函数不会对当前对象产生影响。且就是因为static修饰的时候不支持this,所以才造成static修饰的成员变量不受某一确定对象的限制。
static修饰的成员变量算作类的成员,但在计算类的大小时,不算在其中。
如在阅读中发现错误,或者不准确的地方,请在评论区留言。希望大家支持!