类与对象(一)
一.类和对象的初步认识及类的引入:
1.关于类和对象的初步认知:
在C++中引入类的对象的概念;类是指类型,类别;类和对象本质映射的是现实世界;
C语言是面向过程,关注的是过程,分析出求问题的步骤;
C++是基于面向对象,关注的是对象,将一件事拆分成不同对象,靠对象之间交互完成;
2.类的引入:
类是通过结构体来建立的;C语言中,结构体中只能定义变量;
C++中结构体不仅可以定义变量,还可以定义函数;
struct Student {
void SetStudentInfo(const char* name, const char* gender, int age) {
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void PrintStudentInfo() {
cout<<_name<<" "<<_gender<<" "<<_age<<endl;
}
char _name[20];
char _gender[3];
int _age;
};
int main() {
Student s;
s.SetStudentInfo("Peter", "男", 18);
return 0;
}
在C++中类的定义更喜欢用关键字class来代替;
二.类的定义:
1.类的结构:
class className {
// 类体:由成员函数和成员变量组成
};
class为定义类的关键字,className为类的名字,{}中为类的主体,注意类定义结束时后面分号。 类中的元素称为类的成员;类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。
2.类的两种定义方法:
(1) 声明和定义全部放在类体中,需要注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理;
class Person{
pubilc:
//显示基本信息
void showInfo(){
cout<<_name<<"-"<<_sex<<"-"<<_age<<endl;
}
pubilc:
char*_name;
char *_sex;
char*_age;
};
(2)声明放在.h文件中;类的定义放在.cpp文件中;
//声明放在类的文件person.h中
class Person{
public:
//显示基本信息;
void showInfo();
pubilc:
char*_name;
char *_sex;
char*_age;
};
//定义放在类的实现文件中person.cpp中
#include “person.h"
//显示基本信息:实现:输出,名字,性别,年龄
void Person::showInfo(){
cout<<_name<<"-"<<_sex<<"-"<<_age<<endl;
}
三.类的访问限定符及限定:
C++的封装实现方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用;
1.类的访问限定符:
public(公有) ; protect(保护); private(私有);
2.关于访问限定符的说明:
(1) public修饰的成员在类外可以直接被访问 ;
(2) protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的);
(3) 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止;
(4) class的默认访问权限为private,struct为public(因为struct要兼容C);
访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别;
3.关于封装的知识点:
C++面向对象的三大特性:封装性,继承性,多态性;
(1)在类和对象(一)中,我们只研究类的封装特性,那什么是封装呢?
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互;
(2)关于封装的理解:封装本质就是对代码的管理;
C语言中封装主要是把数据和方法进行分离;而C++中封装一共分为两层:第一层是封装类–把数据和方法都封装到类里面去了,为了方便管理;第二层封装是三个访问限定符:公有—在类外面直接可以访问;私有和保护————只能在类里面进行;(低耦合高类聚)
封装的优点:好修改代码;
问题:C++中struct和class的区别是什么?
解答:C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。 和class是定义类是一样的,区别是struct的成员默认访问方式是公有的,class是的成员默认访问方式是私有的。
四.类的实例化:
1.什么是类的实例化???
用类类型创建对象的过程,称为类的实例化;
举例代码如下:
#include <iostream>
using namespace std;
class Person {
public:
void PrintPersonInfo();
private:
char_name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域 ;
void Person::PrintPersonInfo() {
cout<<_name<<" "_gender<<" "<<_age<<end;
}
int main(){
Person P1;
Person P2;
P1.PrintPersonInfo();
//strcpy(P1._name, "xiaowang"); //会产生报错;如果去掉private就会变成公有的,就编译通过了;
return 0;
2.关于类的实例化注意事项:
(1) 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;
(2) 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量;
(3)类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什 么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间;
五.类对象模型:
关于类对象模型中,本文我们重主要搞清楚类对象大小是如何计算的以及类对象的存储方式;
我们知道在C语言中关于结构体的大小计算是结构体中成员变量之和,符合内存对齐原则;但在C++
类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大 小?
clss A {
public:
void PrintA {
cout<<_a<<endl;
}
private:
char _a;
}
我们通过一段代码来进行解析:
#include <iostream>
using namespace std;
class A{
public:
void PrintA(){
cout<<_a<<endl;
}
private:
char _a;
};
int main(){
cout<<sizeof(A)<<endl;
// A.aa1;
// aa1._a=10;
// aa1.PrintA();
return 0;
}
代码的执行结果为:
当去掉代码中的private后,变为公有,执行结果为:
因此可以得出结论:一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐;
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类;
2.关于结构体的内存对齐规则:
(1) 第一个成员在与结构体偏移量为0的地址处;
(2) 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处;
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
(3 ) 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍;
(4) 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是 所有最大对齐数(含嵌套结构体的对齐数)的整数倍;
3.为什么要进行内存对齐??
数据存在内存中CPU要进行读数据就要取出来,CPU在读的过程中CPU有多少个位就读多少根线,有多少根线就读多少个字节;线越多一次读的就越长,不对齐的话在读取某个特定的字节时可能会多次读取,很麻烦;而内存对齐就是一种空间换时间;
六.this指针;
this指针在C++中的应用是非常广泛的,也是非常重要的一个知识点;
1.什么是this指针???
我们通过代码来举例:
#include <iostream>
using namespace std;
class Date{
public:
void Display(){
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
void SetDate(int year , int month , int day) {
_year = year;
_month = month;
_day = day;
}
private:
int _year ;
int _month ;
int _day ;
};
int main(){
Date d1, d2;
d1.SetDate(2018,5,1);
d2.SetDate(2018,7,1);
d1.Display();
d2.Display();
return 0;
}
输出结果如下:
对于上述类,有这样的一个问题:
Date类中有SetDate与Display两个成员函数;函数体中没有关于不同对象的区分,那当s1调用SetDate函 时,该函数是如何知道应该设置s1对象,而不是设置s2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“成员函数“增加了一个隐藏的指针参数,让该指 针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访 问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成;
实现原理如下:
this指针存在栈上,因为this指针是一个形参,在调用函数的时候生成,只是把地址传给他而已;