文章目录
一、C++的C++的面向对象上
2、面向对象初识
3、声明和定义的区别
4、C++成员函数和成员对象的存放位置
5、this指针
初学C++肯定一开始绕不开的肯定就是面向对象啦!!
作为一个曾经从面向过程转变而来开始接触面向对象思维的我来讲,还是有对面向对象这个概念模糊不清的盲点知识,不过运到困难的最好办法就是战胜困难!,嘻嘻,那开始下面的介绍吧
**
一、首先什么是面向对象
**
1.1 在我们学习C语言的时候,总是听别人说面向对象和面向过程的两种区别,内心是感到很困惑的,听不懂,又很想去研究,没错机会来了,那接下来就告诉你什么是面向对象
1.C语言时面向过程的,关注的时过程,分析出求解问题的步骤,通过函数逐步解决问题
2.c++是基于对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间交互完成
相信大家对面向对象有大概的了解了吧,没懂的话不着急,接下来我们结合C语言的知识在做个大概的了解
**
1.2 C++对类的引入
**
c语言中,结构体只能定义变量,在C++中,结构体不仅可以定义变量,也可以定义函数
1、C语言中struct是用来定义结构体
2、C++中,是使用struct定义结构体的用法,但是同时struct也可以用来定义类
3、C++使用class 和 struct定义类的区别-》默认的访问限定符
```//C语言的风格
struct listnode
{
struct listnode* listnode_next;
};
int main()
{
struct listnode *head;//C的风格
return 0;
}
可以先理解struct(结构体)和class(类)很类似,平时我们在写结构体的时候,总是觉得吧定义一个结构体变量比较长偷懒一点的写法都用typedef,但是你知道吗C++有一个更好的解决办法
//C++的风格
struct listnode
{
listnode* listnode_next;
};
int main()
{
listnode *head;//C++的风格
return 0;
}
这样子一来是不是就觉得省事多了少写了很多的代码
不过宁为要注意的是C语言的结构体默认缺省值是public
而C++的默认缺省值是private,这一点请大家务必注意
**
声明和定义的区别:
**
声明是一种承若,承若要干啥,但是还没做,定义就是
把这个事情落实了
类实例化处对象,相当于定义出了类的成员变量
class Date
{
public:
Date()
{
_a = 0;
_b = 0;
}
private:
int _a;//成员变量的声明
int _b;//成员变量的声明
}
int main()
{
Date d;//实例化对象
return 0;
}
**
C++成员函数和成员对象的存放位置
**
每一个对象中成员变量是不同的,但是调用同一份函数,如果按照此方式存储,当一个类创建对象时,每一个对象都会存放一份代码(函数是存放在代码区的),相同代码保存多次,浪费空间,那么如何解决呢?
答案是成员变量跟成员函数分块存储,成员变量是存放在对象里的,成员函数是存放在类里的,公共区域
注:对象不保存成员函数,只保存成员变量,成员函数存放在公共的代码段
**
一个类对象占用多少个字节?
**
#include<iostream>
using namespace std;
class A
{
public:
void func()
{
}
private:
int _a;
char _b;
};
class B
{
public:
void func()
{
}
};
class C
{
};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;//8字节,涉及内存对齐
cout << sizeof(b) << endl;//1字节
cout << sizeof(c) << endl;//1字节
return 0;
}
可以看出空类和只有一个成员函数的生成的类对象好像都是一样的
那为什么对象a却是8个字节呢
a 对象int _a默认占四个字节,_b本生大小1字节,后面补齐3个字节,总的大小为8个字节,宁外函数体是不占用字节的,他存放在代码区,以上两种情况都是占1个字节因为成员函数不存放在对象中,那为什么要这样子设计呢既然对象不存放成员函数那这多出来的一字节真的就没有用吗?其实不是
存一个字节不是为了存数据,而是占位,表示对象存在
结构体内存对齐规则
1、第一个成员在于结构体偏移量为0的地址处 2、其他成员变量要对齐到某个数字(对齐数)第整数倍数的地址处 (注意:对齐数 =
编译器默认的一个对齐数与该成员大小的较小值,vs默认对齐8字节)
3、结构体总大小为:最大对齐数(所有变量类型最大者与默认对其参数取最小)的整数倍数
4、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍数处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
**
this指针
**
我们先来定义一个日期类Date
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; } 123456789
对于上述类,有这样的一个问题:
Date类中有SetDate与Display两个成员函数,函数体中有没有关于不同对象的区分,那当s1调用SetDate函数
时,该函数是如何知道应该确认是s1对象调用,而不是s2对象调用的呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参
数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该
指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
**
this的特性
**
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this 形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户 传递
void print()
{
cout << "_year = " << _year << "_month = " << _month << "_day = " << _day << endl;
}
int main()
{
a.print();//相当于 a.print(&a),将对象的地址传递给print()函数
}
预处理阶段谁去调用this指针,this指针就指向谁
void print(Date* this) //隐藏的this指针
{
cout << "_year = " << this -> _year << "_month = " << this -> _month << "_day = " << this -> _day << endl;
//相当于在主函数中、printf(&b);
}
每次对象去调用类的成员函数时,都会把改对象的地址传递给this这个隐藏的形参,他是成员函数的第一个参数,注意成员函数时不存放成员变量的而在成员函数中访问成员变量的时候都是通过this指针来操作的
void init(Date *this,int year,int month,int day)
{ //Date *this隐藏的this指针作为函数的第一个参数
this -> _year = year;//this是编译器默认加上,程序员可写可不写
this -> _month = month;
this -> _day = day;
}
谁去调用了void init(Date *this,int year,int month,int day) 那么this指针就指向这个对象,成员函数里面原本是没有成员变量的,只不过都是通过this的形式访问
空指针异常
这一行的原因,先分析在解决,留心报错信息
A1 *point = NULL;
point->print();// 错误,空指针异常
为什么会报这个错误? point -> print(&point),传递进去的是 point这个对象
注:谁去调用成员函数,this指针就指向谁,
既然在上面第一行就已经将NULL赋值给了point指针,此时的point已经指向NULL了,在调用print的时候又将point当作参数传递给隐藏的this指针
那么此时在用成员函数访问成员变量的时候,注:因为成员函数里面是没有成员变量的,他只是通过隐藏的this指针来访问类的成员变量的,那隐藏的this指针也指向NULL(0x0000000)了,那this还能不能通过得到对象的地址去访问类对象的成员变量吗,答案是不能,没有真正对象的地址就没有访问权限,就去读一块不是你的内存那么必然就会程序奔溃
在这一块却又能正常运行,难道是因为this没有传递进去吗?显然不是,指向空的point还是传递给this了,只是因为并没有使用这个此时指向NULL的隐藏指针去访问该类的成员,那么就不会去访问一块不是你的内存而导致编译错误
this指针存放在哪里?
答:存放在栈上的,因为他是一个形参 (vs下是在ecx这个寄存器上)
常见寄存器:eax、ebx、ecx
谢谢大家抽出时间来看,本人还会再接再厉,下一章的内容是面向对象(中)