一、类的定义
1.1类定义格式
class A
{
};
这便是类类型的定义格式,class为定义类的关键字,A为类的名字,{}中为类的主体,注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的⽅法或者成员函数。
因为C++是兼容C语言的,所以在C++中,struct同样可以用来定义类
struct A
{
};
与class定义类类型相似,struct为定义类的关键字,A为类的名字,{}中为类的主体,他们两之间的区别我们在后面会讲到。
注意:我们在定义类的成员变量时一般会加上一个特殊标识,如成员变量前⾯或者后⾯加_ 或者m 开头,这样做的目的主要是区分类的成员变量和类成员函数中的形参变量。
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
// 为了区分成员变量,⼀般习惯上成员变量
// 会加⼀个特殊标识,如_ 或者 m开头
// 成员变量只是声明,不是定义,因为他们没有开辟空间
int _year; // year_ m_year
int _month;
int _day;
};
来看上述代码,如果不在成员变量前面加上一个特殊标识,那么在成员函数Init中成员变量和形参就会分辨不清。
1.2 访问限定符
我们就以刚才的日期类来举个例子:
#include<iostream>
using namespace std;
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << "" << _year << "-" << _month << "-" << _day;
}
private:
// 为了区分成员变量,⼀般习惯上成员变量
// 会加⼀个特殊标识,如_ 或者 m开头
int _year; // year_ m_year
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init(2024,7,18);
d1.Print();
return 0;
}
我们在主函数定义了一个日期类d1,输入d1._year编译器会报错。
说明了私有成员是无法在类外进行访问的,而Init函数是类中的成员函数,在类内即可访问私有的成员变量。
而我们通过类内的成员函数便可以访问私有成员变量。
访问限定符的几点注意事项:
1.访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到 }即类结束。
2.class定义成员没有被访问限定符修饰时默认为private,struct默认为public。这点区别就是我们上面所讲到的用class和struct定义类的区别。
3.⼀般成员变量都会被限制为private/protected,需要给别⼈使⽤的成员函数会放为public。
1.3 类域
class A
{
public:
void Print();
};
class B
{
public:
void Print();
};
此时我们定义了两个类,分别是A和B,此时编译器不会报错,但两个Print函数之间也没有构成函数重载,因为两个Print函数分别处于两个不同的作用域,我们如果要实现Print函数,就要指定作用域,是实现A的还是B的,不然编译器分不清我们实现的是谁的Print函数,所以需要我们使⽤ :: 作 ⽤域操作符指明成员属于哪个类域。
#include<iostream>
using namespace std;
class A
{
public:
void Print();
};
class B
{
public:
void Print();
};
void A::Print()//类A的Print
{
cout << "A::Print" << endl;
}
void B::Print()//类B的Print
{
cout << "B::Print" << endl;
}
int main()
{
A a;
B b;
a.Print();
b.Print();
return 0;
}
结果:
注意:当类中的成员函数声明与定义分离时,就需要指定类域。
二、实例化
2.1 实例化的概念
int main()
{
A a;
B b;
a.Print();
b.Print();
return 0;
}
上述代码的a和b便是类实例化后的对象。
2.2 类对象的大小
类所实例化的每个对象中都包含着成员变量,那么是否包含成员函数呢?答案其实是不包含的,每个对象都必须要有自己的成员变量,但成员函数却并不需要,因为成员函数的逻辑都是一样的,如果我们实例化很多个对象都包含着成员函数是没有必要的,成员函数在编译链接时便能找到地址,不需要再存储。
那么我们怎么判断类对象的大小呢?我们在学C语言结构体的大小时学到过内存对齐的规则,其实C++的类的大小也与内存对齐有关,我们只需按照计算C语言结构体的大小去计算类的大小即可。
内存对齐规则:
1.第⼀个成员在与结构体偏移量为0的地址处。
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
3.注意:对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值。
4.VS中默认的对⻬数为8
5.结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。
6.如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
};
class B
{
public:
void Print()
{
//...
}
};
class C
{
};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
return 0;
}
下面我们我们来计算一下上面代码的三个类的大小。
通过内存对齐的规则我们可以很容易得计算出a的大小为8字节,但类B和C中一个只存放了成员函数,一个什么都没有存放,为什么他们都占1个字节呢?按道理来说不应该1个字节都不占吗?
这里给一个字节是因为要表示对象的存在,因为如果⼀个字节都不给,怎么表⽰对象存在过呢!所以这⾥给1字节,纯粹是为了占位标识对象存在。
三、this指针
我们来看下列代码:
#include<iostream>
using namespace std;
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << "" << _year << "-" << _month << "-" << _day;
}
private:
// 为了区分成员变量,⼀般习惯上成员变量
// 会加⼀个特殊标识,如_ 或者 m开头
int _year; // year_ m_year
int _month;
int _day;
};
int main()
{
Date d1;
Date d2;
d1.Init(2024,7,18);
d1.Print();
d2.Init(2024, 7, 19);
d1.Print();
return 0;
}
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init和 Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了 ⼀个隐含的this指针解决这⾥的问题。
总结:
以上就是我对于类和对象(上)的理解,如果对你有帮助的话,记得一键三连,感谢大家。