一、类的定义
C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
C++同时对struct进行了升级,把struct 升级成了类
1、结构体名称可以做类型
2、里面可以定义函数
//结构体的定义,在C++中更喜欢用class来代替 class U { int a; char b; int add(int x, int y) { return x + y; } };
class 为 定义类的关键字, 类中的元素称为 类的成员: 类中的 数据 称为 类的属性 或者 成员变量 ; 类中的 函数 称为 类的方法 或者 成员函数。
- 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
- 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量
1.1 类的两种定义方法
1.1.1 声明和定义全部放在类体中
class U
{
public:
int a;
char b;
int add(int x, int y)
{
return x + y;
}
};
成员函数如果在类中定义,编译器可能会将其当成内联函数处理
1.1.2 声明定义分开,声明放在.h文件中,类的定义放在.cpp文件中
Func.h
class U
{
public:
int a;
char b;
//在类里面定义的函数,默认是inline,内联函数
int mul(int x, int y)
{
return x * y;
}
//在类里面声明,在.cpp里面定义
int Add(int x, int y);
int Sub(int x, int y);
};
Func.cpp
#include "Func.h"
//用'::'符号进行访问
int U::Add(int x, int y)
{
return x + y;
}
int U::Sub(int x, int y)
{
return x - y;
}
实际中,短小函数可以直接在类里面定义, 长一点函数声明和定义分离
一般情况定义和声明分开更好
二、类的访问限定符
2.1 访问限定符
1.public(共有) 2.private(私有) 3.protected(保护)
访问限定符使用:
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- class的默认访问权限为private,struct为public(因为struct要兼容C),两者相反
class U { public: int Add(int x, int y) { return x + y; } private: int a; int b; int c; };
三、类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域。
class U
{
public:
int Add(int x, int y);
private:
int a;
int b;
int c;
};
int U::Add(int x, int y)
{
return x + y;
}
四、类的大小
类对象的存储方式:只保存成员变量,成员函数存放在公共的代码段
//大小:16字节
class A
{
public:
int Add(int x, int y)
{
return x + y;
}
private:
int a;
char b;
double c;
};
//大小:16字节
class B
{
public:
int a;
char b;
double c;
};
//大小:1字节
class C
{
public:
int Add(int x, int y)
{
return x + y;
}
};
一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐(
结构体内存对齐规则
),注意空类(
成员只有函数
)的大小,空类比较特殊,编译器给了空类
一个字节
来唯一标识这个类。
五、this指针
C++ 编译器给每个 “ 非静态的成员函数 “ 增加了一个隐藏的指针参 数,让该指针(this指针)指向当前对象 ( 函数运行时调用该函数的对象 ) ,在函数体中所有成员变量的操作,都是通过该 指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成 。this指针存放在栈里
5.1 this指针的特性
class Date
{
public:
//void Print(Date* const this)
void Print()
{
//cout << this->_year << this->_month << this->_day <<endl;
cout << _year << _month << _day << endl;
}
//void Creat(Date* const this, int year, int month, int day)
//{
// //this指针本身不能修改,因为它是const修饰的
// //但是this指针指向的对象可以被修改
// this->_year = year;
// this->_month = month;
// this->_day = day;
//}
void Creat(int year, int month, int day)
{
//可以看到this指针的存在
cout << this << endl;
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2;
//d1.Creat(&d1,2022,5,17)
d1.Creat(2022, 5, 17);
//d2.Creat(&d2,2022,5,20)
d2.Creat(2022, 5, 20);
//d1.Print(&d1)
d1.Print();
//d2.Print(&d2)
d2.Print();
return 0;
}
特性:
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
5.2 this指针为空的问题
下面这段代码会运行崩溃:
class A
{
public:
//void Print(A* const this)
void Print()
{
//this为空,指向a,使用空指针指向的东西,程序就会崩溃
//cout << this->a << endl;
cout << a << endl;
}
private:
int a;
};
int main()
{
A* p = nullptr;
//p->Print(&p)
p->Print();
return 0;
}
下面这段代码会正常运行:
class A
{
public:
//void Show(A* const this)
void Show()
{
//传空指针没问题
cout << "Show()" << endl;
}
private:
int a;
};
int main()
{
A* p = nullptr;
//类里面只有成员变量,没有成员函数
//不用指针指向函数,可以直接调用函数,跟空指针没关系
//p->Show(&p)
p->Show();
return 0;
}