类的定义
类的定义格式
类:具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。
定义类的关键字:class
这里定义一个栈类来举例
class Stack//定义一个栈
{
public:
void Init(int capacity=4)
{
_array=(int*)malloc(sizeof(int)*capacity);
assert(_array);
_capacity=capacity;
_top=0;
}
private:
int*_array;
size_t _capacity;
size_t _top;
}
类名是“Stack”,在“{}”里的是类的主体。在类里面的函数与变量称为类的成员,函数称为成员函数,变量称为成员变量。
在类中定义的函数一般默认是“inline”
成员变量: 一般为了区分成员变量,我们会在成员变量前加一个特殊标识符。
int*_array;
size_t _capacity;
size_t _top;
class(类)与struct的区别:
初学类的朋友,可能会觉得class与struct相似,这里我们简单讲讲两者的区别。
- 类中内容称为类的成员,类中的变量称为类的成员变量或者类的属性
- 类中可以定义函数,类中的函数称为类的方法或者类的成员函数
- 用栈来举例,结构体中放的只是我们需要的数据,方法是单独写的,但是在类中我们把这些都放在了class的主体中了
- 类可以直接使用类名,不需要使用typedef来重命名。(类名就是类型)
在c++中,不仅保留了struct原来的功能,还对struct进行了拓展,在c++中也可以用struct来定义类
//用struct来定义一个Person类
struct Person
{
public:
void PersonInit(const char*name,int age,int tel)
{
strcpy(_name,name);
_age = age;
_tel = tel;
}
void Print()
{
cout << "名字:" << _name << endl;
cout << "年龄:" << _age << endl;
cout << "号码:" << _tel << endl;
}
private:
char _name[20];
int _age;
int _tel;
};
访问定义符
C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接⼝提供给外部的用户使用。
访问限定符:
- public:被修饰的内容为公共的,在类外能直接访问
- private:被修饰的内容为私有的,类外不能直接访问
- protected:被修饰的内容被保护的,类外不能直接访问
关于“private”与“protected”的区别,需要到继承的内容中才能体现出来,这里不多阐述。
关于访问权限的作用域 :从访问限定符本身开始,到下一个访问限定符为止。
public:
void Init(int capacity=4)
{
_array=(int*)malloc(sizeof(int)*capacity);
assert(_array);
_capacity=capacity;
_top=0;
}
private:
int*_array;
size_t _capacity;
size_t _top;
比如在这段代码中,public的作用域就是从自身开始到private上面的“}”结束,priveta的作用域就是从自身开始,知道最后。
一般成员变量是private,成员函数是public,因为成员变量中保存着我们所需要的数据,为了不让数据能被轻易的破坏,就设置private来进行保护。
若class中没有给出访问限定符,默认为private,struct中若没给出访问限定符,默认为public
但在类里面,不管成员是私有的还是公有的,都能直接访问。
类域
域的作用是影响编译器的查找,做到名字的隔离
如果不指定类域,编译器在编译时将不会访问类域
Stack.h头文件
#pragma once
#include<iostream>
#include<assert.h>
class Stack
{
public:
void Init(int capacity = 4);
private:
int* _array;
int _capacity;
int _top;
};
Stcak.cpp文件
#include"Stack.h"
void Stack::Init(int capacity)//如果这里没有stack::编译器将会报错。因为没有指定类域,所以编译器在编译时不会到Stack中查找,那么Stack中的成员变量对于编译器来说就是不存在的,所以对于三个不存在的变量进行赋值,这是不被允许的。
{
_array = (int*)malloc(sizeof(int)*capacity);
assert(_array);
_capacity = capacity;
_top = 0;
}
类的实例化
- 用类类型在物理内存中创建一个对象的过程,称为类实例化出对象。
- 类就好比一张房屋设计图纸,告诉了人们这个房是怎么样的,几间房,房多大。类就是告诉程序员实例化出的对象有哪些成员变量。
- 一个类可以实例化出多个对象,类与对象的关系是一对多1->N。
class Data
{
private://这是声明
int _year;
int _month;
int _day;
};
int main()
{
//这是类定义一个对象,也叫类实例化出对象
Data d1;
Data d2;
}
//类与对象的关系:1对多,一个类可以实例化出多个对象。
对象大小
类实例化出每个对象,都会在创建一个独立的数据空间,在对象中肯定存储了成员变量,那成员函数是否会被保存对象存储?答案是不会的。
首先,函数被编译时会被编译成一段指令,对象中无法存储,另外这些会被存储在一个独立空间(代码段),那么,对象若想要存储成员函数就只能存储它的指针,但是存储它的指针这有必要吗? 没必要
class Data
{
public:
void Init(int year,int month,int day)
{
_year=year;
_month=month;
_day=day;
}
void Print()
{
cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
}
private://这是声明
int _year;
int _month;
int _day;
};
int main()
{
//这是类定义一个对象,也叫类实例化出对象
Data d1;
Data d2;
d1.Init(1,1,1);
d2.Init(2,2,2);
d1.Print();
d2.Print();
}
//类与对象的关系:1对多,一个类可以实例化出多个对象。
用这段代码举例,定义两个对象d1与d2,在初始化时,不同之处就是传入的初始值不同,调用的是同一个函数,那么我们还有必要每创建一个对象就把成员函数保存到对象中吗?完全没必要,如果保存了,还会造成没必要的空间浪费。
调用函数被编译成汇编指令[call 地址],其实在编译链接时就要找到函数指针,而不是在运行时查找。
成员函数被放到一个公共区域,成员变量被保存到对象中去。
内存对齐
计算对象大小时,也存在内存对齐规则,与结构体一样:
-
第⼀个成员在与结构体偏移量为0的地址处。
-
其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
-
注意:对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值。
-
VS中默认的对⻬数为8
-
结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍。
-
如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。
先来一段代码举例:
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
int _i;
};
计算A实例化对象的大小
A中,存在两个成员变量 _ch 与_i
_ch是char类型,又是第一个元素,那么它放在偏移量为0的地址出,占1字节
再来两段代码:
class B
{
public:
void Print()
{
//...
}
};
************************
class C
{};
类B与C中没有成员变量,那么它的大小是多少字节?答案是1字节。
为什么没有成员变量,还要占1字节?原因很简单:这1字节就是用来占位的,表示对象存在过。
this指针
c++中提供了一个this指针,同来区分函数是被d1调用还是被d2调用。
在编译器编译后,会在函数实参与形参的第一个位置隐示生成一个this指针。
类的成员函数中访问类的成员变量的本质就是通过this来访问。
c++中规定,this指针不能在实参与形参中显示的写入,但能在成员函数中显示的使用
class Data
{
public:
//void Init(Data *const this,int year,int month,int day)
void Init(int year,int month,int day)
{
_year=year;
_month=month;
_day=day;
}
//void Print(Data *const this)
void Print()
{
//cout<<this->_year<<'/'<<this->_month<<'/'<<this->_day<<endl;
cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
//这是类定义一个对象,也叫类实例化出对象
Data d1;
Data d2;
/*
d1.Init(&d1,1,1,1);
d2.Init(&d2,2,2,2);
*/
d1.Init(1,1,1);
d2.Init(2,2,2);
/*
d1.Print(&d1);
d2.Print(&d2);
*/
d1.Print();
d2.Print();
}
//类与对象的关系:1对多,一个类可以实例化出多个对象。