const
const在*的左边,const修饰的是指针的指向能力
const在*的右边,const修饰的是指针自身的能力
int main()
{
int a = 10, b = 20;
const int* p = &a;//修饰的是指针的指向能力
int* s0 = p;//error
const int* s1 = p;
int* const s2 = p;//error
const int* const s3 = p;
}
能力可以收缩
int main()
{
int a = 10, b = 20;
int* const p = &a;
int* s0 = p;
const int* s1 = p;
int* const s2 = p;
const int* const s3 = p;
}
*是和变量名结合
int main()
{
int a = 10, b = 20;
int* p = &a;
int* s = p;
int*& pref = p;//从右向左一次解析
int&* pref = p;//error
}
int main()
{
int*& pref = p;
const int*& pref = p;
int* const& pref = p;
int*& const pref = p;
}
设计一个类型,设计成员函数
class CGoods //设计类型
{
public:
char Name[21];//设计成员数据
int Amount;
float Price;
float Total_value;
public:
void RegisterGoods(const char*, int, float);
void CountTotal(void);
void GetName(char[]);
int GetAmount(void);
float GetPrice(void);
const float GetTotal_value(void)//返回的数值是常性
{
return Total_value;
}
float GetTotal_value(void) const//此方法为常方法
{
return Total_value;
}
};
void CGoods::RegisterGoods(const char *name, int amount, float price)
{
strcpy_s(Name,21,name);
Amount = amount;
Price = price;
}
void CGoods::CountTotal(void)
{
Total_value = Price * Amount;
}
void CGoods::GetName(char name[])
{
strcpy(name, Name);
}
int CGoods::GetAmount(void)
{
return (Amount);
}
float CGoods::GetPrice(void)
{
return(Price);
}
各对象有完全独立地安排内存的方案
区别同一个类所实例化的对象,是由属性(数据成员)的值决定的
代码为所有对象共享
此时引入this指针
编译器对类型的编译分为三步:
(1)首先识别属性成员
(2)对类里面的函数的声明(函数原型)进行识别
(3)改写 (类的成员函数加this指针)
const float GetTotal_value(void)//返回的数值是常性
{
return Total_value;
}
float GetTotal_value(void) const//此方法为常方法
{
return Total_value;
}
int main()
{
const int a = 10;
int b = 20;
int* p1 = &a;//error
const int* p2 = &a;
int* const p3 = &a;//error
const int* const p4 = &a;
}
常对象只能调动常方法,普通对象可以调动常对象和常方法
thiscall仅仅应用于"C++"成员函数。this指针存放于ECX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定
_cdecl —C的调用约定
void __cdecl CountTotal(void)
{
this->Total_value = this->Price * this->Amount;
}
C++的成员函数,它的this指针是怎么样进行传递的
如果用对象. 调用成员方法时,在逻辑上是面向对象的,物理上是面向过程的,把对象的地址传递给成员函数的this指针
对象的地址是如何传递的?
对于C++来讲,C++的调用约定是thiscall,传递的时候,直接给出ecx,获取对象的地址,到达成员函数内部时,使用mov指令将ecx的值给this指针
什么时候以入栈的形式将参数调用?改写为C的调用约定
在成员函数前面加上(两个_)__ cdecl
取eax的地址,push eax,直接将eax给函数的形参,给this指针
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ba0b1Qd2-1646786742655)(C:\Users\86180\AppData\Roaming\Typora\typora-user-images\image-20220307191152991.png)]
C比C++多一个入栈
4.构造函数和析构函数
类的所有属性成员,公有成员可能通过花括号进行初始化,初始化应该初始化所有成员
数据成员多为私有的,要对它们进行初始化,必须用一个共有函数来进行,同时这个函数应该在且仅在定义对象时自动执行一次,称为构造函数
构造函数用途:(1)创建对象(2)初始化对象中的属性(3)类型转换
既然构造函数创建对象,那么空间是谁创建的?
空间(系统分配而来)只能申请,不能创建
class Pointer
{
private:
int row;
int col;
public:
Pointer()
{
row = 0;
col = 0;
}
Pointer(int r, int c)
{
row = r;
col = c;
}
};
int main()
{
Pointer c1(12, 23);//有括号必须带参数
Pointer c2;//不带参数就不要加括号
Pointer c2 = Pointer(10,20);
Pointer c3();//函数的声明
}
存储空间与对象的关系:
以列表方式初始化成员变量或成员对象
new按照关键字调用有两个方案:
(1)malloc ,从堆区申请空间
(2)调动类型,在空间构建对象
(3)返回构建对象的地址
class Pointer
{
private:
int row;
int col;
public:
Pointer()
{
row = 0;
col = 0;
}
Pointer(int r, int c)
{
row = r;
col = c;
}
};
Pointer g_pt(12, 23);//全局对象 .data
int main()
{
Pointer p1(100, 200);//局部对象 .stack
Pointer* p = NULL;
p = new Pointer(10, 20);
//new运算符调用
Pointer* s = (Pointer*)malloc(sizeof(Pointer));//heap,这个空间没有对象
//定位new
new(s) Pointer(12, 23);//在s指向的空间,调动构造函数,构建对象
s->~Pointer();//释放空间的资源
free(s);//释放空间
s = NULL;
delete p;
//1.调动p所指对象的析构函数,s->~Pointer();
//2.释放内存空间
}
class Object
{
private:
int val;
public:
Object(int x)
{
val = x;
cout << "Create:" << val << endl;
}
};
Object ObjA(1);//程序运行前创建
int main()
{
Object ObjB(2);
}
Object ObjC(3);//程序运行前创建
此段代码的输出是:
构建完全局对象之后才进入到主函数
构造与析构函数的区别,对象的生存期;
动态创建类的对象,所谓动态指在程序运行时建立对象
class Object
{
private:
int val;
public:
Object(int x)
{
val = x;
cout << "Create:" << val << endl;
}
};
Object ObjA(1);//程序运行前创建
int main()
{
Object ObjB(2);
}
Object ObjC(3);//程序运行前创建
此段代码的输出是:
构建完全局对象之后才进入到主函数
构造与析构函数的区别,对象的生存期;
动态创建类的对象,所谓动态指在程序运行时建立对象