1、类定义
最简单来说,类就是定义了一个新的类型和新的作用域。
class Student
{
//类体;由类成员(成员函数和成员变量等)组成
};//后面一定要加上分号(因为在类定义之后可以接一个对象定义列表)
class为定义类的关键字,Student为类的名字,{}为类的主体,后面分号不能丢。
类中的元素成为类的成员,类中数据称为类的属性或类的成员变量;类中的函数称为类的方法或者类的成员函数。
类的两种定义方式:
(1)类的声明和定义全部放在类体中(正式场合尽量不要使用)
class Student
{
public:
//显示基本信息
void ShowInfo()
{
cout << _name << ' ' << _gender << ' ' << _age << endl;
}
char _name[20];
char _gender[3];
int _age;
};
(2)类的声明放在/.h头文件中,类的定义放在/.cpp源文件中
//.h
class Student
{
public:
void ShowInfo();
char _name[20];
char _gender[3];
int _age;
};
//.cpp
#include"Student.h"
void Student::ShowInfo()
{
cout << _name << ' ' << _gender << ' ' << _age << endl;
}
2.数据抽象和封装
类背后蕴涵的基本思想是数据抽象和封装。
数据抽象是一种依赖于接口和实现分离的编程技术,我们只需知道类是如何实现的就可以,不必深究。
封装是一项将低层次的元素组合起来形成新的、高层次实体的技术。函数是封装的一种形式。
访问限定符实施抽象和封装:
在C++中,使用访问限定符来定义类的抽象接口和实施封装。一个类可以没有访问限定符,也可以有多个。
【访问限定符说明】
(1)public(公有)成员在类外可以直接访问;
(2)protected(保护)和private(私有)成员在类外不能够访问;
(3)他们的作用域从该访问限定符出现的位置开始直到下一个限定符出现为止;
(4)class的体中如果没有定义限定符,默认访问限定符为private;
(5)struct为public型(因为要兼容C)
3.类定义的更多内容
(1)使用类型别名来简化类(typedef)
(2)成员函数可以被重载
/.h
class Test
{
public:
typedef std::string::size_type index;
char Get() const;
char Get(index height, index weight) const;
private:
std::string contents;
index _name;
index _height, _weight;
};
/.cpp
char Test::Get() const
{
return contents[_name];
}
int main()
{
Test s;
char ch = s.Get();
ch = s.Get(0,0);
return 0;
};
3.显示指定inline成员函数
在类内部定义的成员函数,例如不接受实参的Get成员,将自动作为inline处理。也可以显示的将成员函数声明为inline。
class Test
{
public:
typedef std::string::size_type index;
char Get() const;
inline char Get(index height, index weight) const;
private:
std::string contents;
index _name;
index _height, _weight;
};
4.类的作用域
(1)在类体外定义成员,需使用::作用域解析符指明成员属于哪个类域;
(2)在类的作用域外,只能通过对象(或指针)借助成员访问操作符.和->来访问类成员。
5.类的实例化
用类类型创建对象的过程,称为类的实例化
(1)类只是一个模型一样的 东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储他
(2)一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间存储类成员变量
/.h
class Student
{
public:
void SetInfo(char *name, char *gender, int age);
void ShowInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
/.cpp
void Student::SetInfo(char *name, char *gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void Student::ShowInfo()
{
cout << _name << '_' << _gender << '_' << _age << endl;
}
int main()
{
//Test s;
//char ch = s.Get();
//ch = s.Get(0,0);
Student s;
s.SetInfo("Bishop", "male", 20);
s.ShowInfo();
system("pause");
return 0;
}
6.类的对象大小的计算
/.h
class Student
{
public:
void SetInfo(char *name, char *gender, int age);
void ShowInfo();
char _name[20];
char _gender[3];
int _age;
};
/.cpp
void Student::SetInfo(char *name, char *gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void Student::ShowInfo()
{
cout << _name << "_" << _gender << "_" << _age << endl;
}
int main()
{
Student s1, s2, s3;
s1.SetInfo("Bishop", "male", 20);
s2.SetInfo("Peter", "male", 21);
s3.SetInfo("Rose", "female", 18);
s1.ShowInfo();
s2.ShowInfo();
s3.ShowInfo();
system("pause");
return 0;
}
(1)存储方式:
方式一:类对象中包含类中的各个成员
缺陷:每个对象中成员变量是不同的,但是函数都是相同的,如果一个类创建多个对象,每个对象中都会保存一份代码,相同代码多次保存,浪费空间。
方式二:多给一个指针,存放成员函数表的首地址
这个方法明显比方式一节省了太多的空间,但是对象中还是多了一个指针。
方式三:只保存对象的具体成员变量,所有成员函数存放在统一的代码公共区。
(2)内存对其规则
a.第一个成员在与结构体偏移量为0的地址处;
b.其他成员变量要对其到某个数字(对齐数)的整数倍的地址处;注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值;(VS中为8,gcc中为4)
c.结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍;
d.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
7.类的this指针
(1)每个成员函数都有一个指针形参,他的名字是固定的,称为this指针,this指针是隐式的;(构造函数比较特殊
没有这个隐含this形参)
(2)编译器会对成员函数进行处理,在对象调用成员函数时,对象地址实参传递给成员函数的第一个形参this指针;
(3)this指针是成员函数隐含指针形参,是编译器自己处理的,我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时显示传递对象的地址给this指针。
例如:
/.h
class Student
{
public:
void SetInfo(char *name, char *gender, int age);
void ShowInfo();
char _name[20];
char _gender[3];
int _age;
};
/.cpp
void Student::SetInfo(char *name, char *gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
/*
void Student::ShowInfo(Student *this)
{
cout << this->_name << "_" << this->_gender << "_" << this->_age << endl;
}
*/
void Student::ShowInfo()
{
cout << _name << "_" << _gender << "_" << _age << endl;
}
int main()
{
Student s1, s2, s3;
s1.SetInfo("Bishop", "male", 20);
s2.SetInfo("Peter", "male", 21);
s3.SetInfo("Rose", "female", 18);
s1.ShowInfo();
s2.ShowInfo();
s3.ShowInfo();
system("pause");
return 0;
}