c++--类(上)

简介: c++--类(上)

C++之类(上)
一、类的定义
1.1 类定义格式
1.2 访问限定符
1.3 类域
二、实例化
2.1 实例化的概念
2.2 对象大小
三、this指针
一、类的定义
1.1 类定义格式
1、class为定义类的关键字,{}中为类的主体,注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的⽅法或者成员函数。

class stack
{
int*arr;
int size;
int capacity;//成员变量

void Push(int x);
int Top();
void Pop();//成员函数

};
1
2
3
4
5
6
7
8
9
10
这个就是一个栈的类,它与结构体不同,类是变量与函数不分离。

2、为了区分成员变量,⼀般习惯上成员变量会加⼀个特殊标识,如成员变量前⾯或者后⾯加_ 或者 m开头。

class direction
{
public:
void Init(int left, int right, int up, int down)
{
_left = left;
_right = right;
_up = up;
down = down;
}
private:
//在这里有两种方式可以用来区分
//1、在成员变量前加

//2、用this指针例如(this->left=left)
int _left;
int _right;
int _up;
int _down;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3、 C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是struct中可以定义函数, ⼀般情况下我们还是推荐⽤class定义类。

struct stack
{
int*arr;
int size;
int capacity;//成员变量

void Push(int x);
int Top();
void Pop();//成员函数

};
1
2
3
4
5
6
7
8
9
10
这个也是可以的。

4、定义在类⾯的成员函数默认为inline。如果我们不想在类里写我们的函数体,就得用::域作用限定符。

class direction
{
public:
void Init(int left, int right, int up, int down);
private:
//在这里有两种方式可以用来区分
//1、在成员变量前加_
//2、用this指针例如(this->left=left)
int _left;
int _right;
int _up;
int _down;
};
void direction::Init(int left, int right, int up, int down)
{
_left = left;
_right = right;
_up = up;
_down = down;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1.2 访问限定符

1、C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接⼝提供给外部的⽤户使⽤。这里的接口指的就是函数。

2、public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的,在继承章节才会体现它俩的不同。

大家可以看到size可以轻易的访问,而Top就不能被访问。

3、访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有访问限定符,作⽤域就到 }即类结束。

class stack
{
public:
int*arr;
int size;
int capacity;//成员变量
//public的范围到private之前
private:
void Push(int x);
int Top();
void Pop();//成员函数
//后面已经没有访问限定符了,那么private的范围到“}”之前
};
1
2
3
4
5
6
7
8
9
10
11
12
13
4、class定义成员没有被访问限定符修饰时默认为private,struct默认为public。

5、最后访问限定符可以多次出现,但实际使用一般不这样写。

1.3 类域
类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤ :: 作⽤域操作符指明成员属于哪个类域。

特别是这种两个类成员函数名字一样的,一定要指明类域。

二、实例化
2.1 实例化的概念
1、⽤类类型在物理内存中创建对象的过程,称为类实例化出对象。

class direction
{
public:
void Init(int left, int right, int up, int down);
private:
//在这里有两种方式可以用来区分
//1、在成员变量前加_
//2、用this指针例如(this->left=left)
int _left;
int _right;
int _up;
int _down;
};
void direction::Init(int left, int right, int up, int down)
{
_left = left;
_right = right;
_up = up;
_down = down;
}
int main()
{
direction d1, d2;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在这里我们就实例化了两个对象d1,d2。

2、类是对象进⾏⼀种抽象描述,是⼀个模型⼀样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,⽤类实例化出对象时,才会分配空间。
什么意思呢?就是我们定义的类只是一个声明,当我们创建对象,例如上面的d1,d2时才会分配空间。

3、⼀个类可以实例化出多个对象,实例化出的对象 占⽤实际的物理空间,存储类成员变量。

2.2 对象大小
类实例化出的每个对象,都有独⽴的数据空间,所以对象中肯定包含成员变量,那么成员函数是否包含呢?⾸先函数被编译后是⼀段指令,对象中没办法存储,这些指令存储在⼀个单独的区域(代码段),那么对象中⾮要存储的话,只能是成员函数的指针。
我们只需要记住在算对象大小的时候,不需要计算成员函数,只计算成员变量。
那现在问题来了,要是我们的类里什么都没有,但我们用它实例化了对象,那实例化后的对象的大小是多少啊?

这⾥给1字节,纯粹是为了占位标识对象存在。

其次我们要算对象的大小我们只需要计算成员变量的大小,其算法与struct的算法一致都是符合内存对齐原则:

那大家有没有想过为什么要内存对齐啊?

三、this指针
首先我们先看一个代码:

class direction
{
public:
void Init(int up, int down, int left, int right)
{
_left = left;
_right = right;
_up = up;
_down = down;
}
public:
int _left;
int _right;
int _up;
int _down;
};
int main()
{
direction d1, d2;
d1.Init(0, 1, 2, 3);
d2.Init(3, 2, 1, 0);
cout << d1._up << ' ' << d1._down << ' ' << d1._left << ' ' << d1._right << endl;
cout << d2._up << ' ' << d2._down << ' ' << d2._left << ' ' << d2._right << endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
为什么这里是同一个函数,打印的确实一样的呢?这里就引入了this指针,this指针通常都是隐含的。

那我们将它恢复回原来的样子:

class direction
{
public:
//void Init(dataconst this,int up,int down......)
void Init(int up, int down, int left, int right)
{
this->_left = left;
this->_right = right;
this->_up = up;
this->_down = down;
}
public:
int _left;
int _right;
int _up;
int _down;
};
int main()
{
direction d1, d2;
d1.Init(0, 1, 2, 3);
//d1.Init(&d1, 0, 1, 2, 3);
d2.Init(3, 2, 1, 0);//d2.Init(data
const this,3,2,1,0);
//d2.Init(&d2, 3, 2, 1, 0);
cout << d1._up << ' ' << d1._down << ' ' << d1._left << ' ' << d1._right << endl;
cout << d2._up << ' ' << d2._down << ' ' << d2._left << ' ' << d2._right << endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
需要注意的是:C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显⽰使⽤this指针。

最后我们需要知道this指针存在于哪个区域,是堆、栈,还是常量区还是对象里?

我们要知道this指针是作为形参传递的对不对,形参存储于栈里,所以在这里栈比较合适,但是由于c++里经常使用this指针,所以有些编译器会将其放入寄存器,但是在做题过程中我们选栈。

这两个题目有助于我们理解this指针,大家可以简单的看下

1、问它运行结果是什么?

include

using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
}
private:
int _a;
};

int main()
{
A* p = nullptr;
p->Print();
return 0;
}
//A、编译报错 B、运⾏崩溃 C、正常运⾏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这个题目选择正常运行,虽然这里p是空指针,但我们这里是将它的地址作为参数传递,成员函数不存于类的变量中,我们访问成员函数并没有通过this指针。

include

using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}//A、编译报错 B、运⾏崩溃 C、正常运⾏

相关文章
|
1月前
|
C++ 容器
C++中自定义结构体或类作为关联容器的键
C++中自定义结构体或类作为关联容器的键
31 0
|
10天前
|
存储 编译器 C++
C ++初阶:类和对象(中)
C ++初阶:类和对象(中)
|
10天前
|
C++
C++(十六)类之间转化
在C++中,类之间的转换可以通过转换构造函数和操作符函数实现。转换构造函数是一种单参数构造函数,用于将其他类型转换为本类类型。为了防止不必要的隐式转换,可以使用`explicit`关键字来禁止这种自动转换。此外,还可以通过定义`operator`函数来进行类型转换,该函数无参数且无返回值。下面展示了如何使用这两种方式实现自定义类型的相互转换,并通过示例代码说明了`explicit`关键字的作用。
|
10天前
|
存储 设计模式 编译器
C++(十三) 类的扩展
本文详细介绍了C++中类的各种扩展特性,包括类成员存储、`sizeof`操作符的应用、类成员函数的存储方式及其背后的`this`指针机制。此外,还探讨了`const`修饰符在成员变量和函数中的作用,以及如何通过`static`关键字实现类中的资源共享。文章还介绍了单例模式的设计思路,并讨论了指向类成员(数据成员和函数成员)的指针的使用方法。最后,还讲解了指向静态成员的指针的相关概念和应用示例。通过这些内容,帮助读者更好地理解和掌握C++面向对象编程的核心概念和技术细节。
|
1月前
|
存储 安全 编译器
【C++】类和对象(下)
【C++】类和对象(下)
【C++】类和对象(下)
|
30天前
|
编译器 C++
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
|
30天前
|
编译器 C++
virtual类的使用方法问题之静态和非静态函数成员在C++对象模型中存放如何解决
virtual类的使用方法问题之静态和非静态函数成员在C++对象模型中存放如何解决
|
30天前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
1月前
|
编译器 C++
【C++】类和对象(中)
【C++】类和对象(中)
|
1月前
|
存储 编译器 程序员
【C++】类和对象(上)
【C++】类和对象(上)