目录
一、编译器对属性和方法的处理机制
1、在C语言中“数据”和“处理数据的函数”是分开来声明的,也就是语言本身并没有“数据和函数”之间的关联性、在C++中,通过抽象数据类型(abstract data type ,ADT),在类定义数据和函数,来实现数据的函数直接绑定。
2、在对象的内存模型中,“数据”和“处理数据的函数”是如何存储的。
先来写一个测试代码:
#include <iostream> using namespace std; class C1 { public: int i; //4 int j; //4 int k; //4 protected: private: }; class C2 { public: int i; int j; int k; public: int getK() { return k; } void setK(int val) { k = val; } S }; int main() { C1 c1; C2 c2; cout <<"size c1 ="<< sizeof(c1) << endl; cout <<"size c2 ="<< sizeof(c2) << endl; }
运行结果如下:
一个int类型占四个字节,然后上述代码中一共有三个int类型的成员变量,4*3=12
C2中的成员函数却不占用内存空间,所以我们可以得出:
C++类成员中的成员变量和成员函数是分开存储的
同一类中的存储位置也有差别:
普通成员变量:
存储于类的对象当中,与结构体struct变量有相同的内存分布和字节对齐方式
静态成员变量:
存储于全局数据区当中
成员函数:
存储于代码段当中
内存存储(高位到低位):系统环境固件>>栈>>堆>>数据段>>代码段
二、this指针
原理:
原理性的问题参考这个文章http://t.csdn.cn/BfFJn
本文主要通过Clion的Terminal的调试来体现this指针的
具体步骤:打开Terminal界面:
//在Terminal的命令行中先输入 g++ -g main.cpp -o main //生成了一个main可执行文件 回车 然后 gdb main //运行一下这一个程序用gdb调试 回车..... 出现(gdb)后输入start命令//运行该语句 n//相当于(next)执行下一条语句 print c2.getK //用print方法打印一下 //打印结果:$1 = {int (C2 * const)} 0x402d10 <C2::getK()>
根据打印结果可知({int (C2 * const)} )编译器自动给形参赋了一个常指针指向c2
(该指针在C++中叫做this指针原型int(C2 * const this)),这是因为C++编译器会将成员函数的第一个形参设计为this指针,this指针指向调用成员函数的首地址,指向成员函数的得对象,在成员函数执行的过程中,正是通过“this指针”才能找到对象所在的地址,在调用c2.getK()的时候相当于getK(&c2);将函数的地址传递了过去。
注意:this的范围使用:非静态的成员函数
this指针代码例程:
#include <iostream> /* * 编译器对属性和方法的处理机制 * 1、 * 在C中”数据“和”函数“是分开来声明的也就是说语言本身并没有“数据和函数”之间的关联性。在C++中, * 通过抽象数据类型(abstract data type,ADT),在类中定义数据和函数,实现了数据和函数的绑定 * 2、 *在对象内存模型中,数据和函数是如何存储的呐 * */ using namespace std; class C1 { public: int i; //4 int j; //4 int k; //4 protected: private: }; class C2 { public: int i; int j; int k; public: int getK() { cout << k << endl; return k; } void setK(int val) { k = val; }//相当于指向调用函数的对象同时再return k; 也就是 return this->k; }; void test1(void)//结果显示c1 c2都占12个字节的空间 { C1 c1; C2 c2; cout << sizeof(c1) << endl; cout << sizeof(c2) << endl; }//得出结论C++的函数不占用对象的内存空间, // 所以可知c++类对象中的成员变量和成员函数是分开存储的 /* * 成员变量: * 普通成员变量:存储于对象中,与struct变量有相同的内存布局和对齐方式 * 静态成员变量:存储于全局数据区当中 * 成员函数: * 存储于代码段中 * * 内存:高》底 * 系统环境固件 * 栈 * 堆 * 数据段 * 代码段 * */ int main() { // test1(); C2 c2,c3; c2.k=100; c3.k=10; c2.getK(); c3.getK(); c2.setK(100); return 0; } //Terminal:调试顺序 /* * g++ -g main.cpp -o main //生成了一个main可执行文件 * 然后运行一下这个程序用gdb调试 * gdb main * 空格、回车 * start命令 * 回车 * n(next)//执行下一条语句 * 用print方法打印一下 * print c2.getK * 打印结果如下: * $1 = {int (C2 * const)} 0x402d10 <C2::getK()> * 编译器自动给形参付了一个常指针指向c2 * (该指针再C++中叫做this指针原类型int (C2 * const this)) * 所以解释:C++编译器会将成员函数的第一个形参设计为this指针, * this指针指向了调用成员函数的首地址,(指向成员函数的对象) * 再成员函数执行的过程中,正是通过“this指针”才能找到对象所在的地址 * 调用c2.getK()时候相当于getK(&c2);将函数的地址传了过去 * 相当于指向调用函数的对象同时再return k; 也就是 return this->k; * { * 打印 * print c2.setK //$1 = {void (C2 * const, int)} 0x402d80 <C2::setK(int)> this指针指向调用该成员函数的对象 * */
三、静态成员
1、静态成员变量:
定义:关键字static可以用于声明一个类的成员,静态成员提供了一个同类的共享机制。
1.1用法:
#include <iostream> using namespace std; class Sheep { public: char name[32]; int age; Sheep() { cout << "Sheep()" << endl; cnt++; } ~Sheep() { cnt--; } static int cnt; //只是声明了一个静态成员变量,不是类或者对象的成员变量,但是他的作用域是在类和这类的所有的实例化对象 }; //定义了Sheep这个类中的静态成员变量cnt,并且初始化为0(如果不初始化默认为0) int Sheep::cnt = 0; int main() { //构造了10个Sheep对象: 购买了10头羊 Sheep *p = new Sheep[10]; cout << Sheep::cnt << endl; Sheep s1; cout << s1.cnt << endl; Sheep s2; cout << sizeof(s2) << endl; cout << Sheep::cnt << endl; cout << s1.cnt << endl; cout << s2.cnt << endl; return 0; }
1.2静态变量的使用:
1.2.1:类内声明static变量
static int cnt;
1.2.2:类外定义初始化:
int Sheep::cnt = 0;
2、静态成员函数:
1、定义:使用static修饰的成员函数叫做静态成员函数
2、性质:在静态成员函数内不能够访问除静态成员变量以外的其他成员变量。
3、使用:
#include <iostream> using namespace std; int cnt = 0; class Sheep { public: char name[32]; int age; Sheep() { cout << "Sheep()" << endl; cnt++; } ~Sheep() { cnt--; } //静态的成员函数 static int sheep_num() //没有this指针 { // cout << age << endl; //静态成员函数中不能访问非静态的成员变量!!! return cnt; //访问静态成员变量 } //public: private: static int cnt; //只是声明了一个静态成员变量,不是类或者对象的成员变量,但是他的作用域是在类和这类的所有的实例化对象 }; //定义了Sheep这个类中的静态成员变量cnt,并且初始化为0(如果不初始化默认为0) int Sheep::cnt = 0; class Math { public: static void sin(){} static void cos(){} static void tan(){} static void cotan(){} }; class searchAlgrithm { //二分查找 }; class sortAlgrithm { //冒泡 //快排法 //堆排序 }; int main() { //构造了10个Sheep对象: 购买了10头羊 Sheep *p = new Sheep[10]; // cout << Sheep::cnt << endl; Sheep s1; // cout << s1.cnt << endl; Sheep s2; cout << sizeof(s2) << endl; // cout << Sheep::cnt << endl; // cout << s1.cnt << endl; // cout << s2.cnt << endl; cout << Sheep::sheep_num() << endl; //建议用类访问静态成员变量和成员函数因为这种访问方式可读性强 cout << s1.sheep_num() << endl; //不会:sheep_num(&s1); Math::sin(); return 0; }
注意:静态成员函数不能够访问对象、类中的成员变量。
因为静态成员函数不属于对象。
用处:
静态成员函数的用处:
-
访问被private/protected修饰静态成员变量
-
可以实现某些特殊的设计模式:如Singleton(单例模式)
-
可以封装某些算法
静态成员总代码:
/* * ————————————————————————————静态成员变量—————————————————————— * 定义:关键词static可以用于声明一个类成员,静态变量提供了同类对象的共享机制 * 把一个类的成员声明为static时,这个类无论由多少个对象被创建这些对象共享这个static成员 * */ #include <iostream> using namespace std; class Sheep { public: char name[32]; int age; Sheep()//构造函数 { cout << "Sheep()" <<endl; cut++; } ~Sheep()//析构函数 { cut--; } //静态成员变量 static int cut;//(之和类有关系)只是声明了一个静态成员变量,不是类或者对象的成员变量,但是他的作用域再类和对象中 //静态成员函数 static int sheep_num() { // cout<< age <<endl;//invalid use of member 'Sheep::age' in static member function(非法的访问了非静态成员变量) return cut;//访问静态成员变量 } }; int Sheep::cut=0;//此处为定义静态变量 /* * 静态变量的使用: * 现在类外边的C文件中的定义,然后在类中声明 * */ /* * ————————————————————————————静态成员函数—————————————————————— * 1、把static修饰的成员函数叫做静态成员函数 * 2、在静态成员函数内不能访问除了静态成员变量之外的其他成员变量 * * * */ int main() { //构造了10个Sheep对象,场景十只羊 Sheep * p=new Sheep[10];//构造了10个对象 cout<<Sheep::cut<<endl; Sheep s1;//第十一个对象 cout<<s1.cut<<endl; Sheep s2;//第十二个对象 cout << sizeof(s2)<<endl; cout << Sheep::cut<<endl; cout<<s1.cut<<endl; cout<<s2.cut<<endl; Sheep s3;//第十三个对象 //通过类和对象都能进行静态成员函数的访问 cout << Sheep::sheep_num() << endl;//建议使用类进行访问静态成员用类进行访问 cout << s3.sheep_num() << endl;//不会:使用到this指针也就不会sheep_num(&s3) return 0; } //静态成员的位置在数据段上对象可以共享 /* * 作用: * 1、用来访问被private:和protected:保护的静态变量 * 2、实现某些特殊结构的设计模式(单例模式) * 3、封装某些算法 * */