类和对象(一)

类和对象的引入

在C语言中,我们喜欢用结构体来对数据进行封装,但是结构对于C语言来说,只能定义变量,在C++中,结构体里面还可以用来定义函数

struct Stack
{
	void init(int n=4)
	{
		arr = (int*)malloc(sizeof(int)*n);
		_top = 0;
		_capacity = n;
	}
	void Destory()
	{
		arr = nullptr;
		_top = _capacity = 0;
	}
	void push(int x)
	{
		//******//   缺少代码
		arr[_top++] = x;
	}
	int* arr;
	int _top;
	int _capacity;
};


int main()
{
	struct Stack stack1;
	stack1.init();
	stack1.push(1);
	stack1.push(2);


	Stack stack2;
	stack2.init();
	stack2.push(1);
	stack2.push(2);
	return 0;
}

C++中的结构体里面定义的函数发生了一些变化,就是有的参数不用写,上面的是我们之前实现的栈,里面的在定义函数的时后需要传递指针参数,但是在C++里面不用,因为这里时写在了类里面

还有,在C++里面,结构的类型可以是它的结构体名称,上面的struct Stack stack1和Stack stack2都是对的

其实,在C++里面,更喜欢把struct替换成为class

class Stack                //替换成为class
{
	void init(int n=4)
	{
		arr = (int*)malloc(sizeof(int)*n);
		_top = 0;
		_capacity = n;
	}
	void Destory()
	{
		arr = nullptr;
		_top = _capacity = 0;
	}
	void push(int x)
	{
		//******//   缺少代码
		arr[_top++] = x;
	}
	int* arr;
	int _top;
	int _capacity;
};


int main()
{
	class Stack stack1;
	stack1.init();
	stack1.push(1);
	stack1.push(2);


	class stack2;
	stack2.init();
	stack2.push(1);
	stack2.push(2);
	return 0;
}

(注意的是,函数如果要定义在类外面,应该像下面这样定义)

void Stack::init(int n)
{
	arr = (int*)malloc(sizeof(int) * n);
	_top = 0;
	_capacity = n;
}

void Stack::Destory()
{
	arr = nullptr;
	_top = _capacity = 0;
}


void Stack::push(int x)
{
	//******//   缺少代码
	arr[_top++] = x;
}

但是替换成为class了之后,我们发现程序会运行错误

这是由于 类的访问限定符号

【访问限定符说明】
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)

3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C) 

类的实例化

用类类型创建对象的过程,称为类的实例化

1.类是对对象进行描述的,就像一个模型,限定的类有哪些对象,对类进行定义并没有分配出实际的内存空间

2.一个类可以实例化多个对象,实例化的对象,占用实际的物理空间,用来存储对象

class Person

{

        int age=10;              //语法错误,不应该赋值,这时候并没有实际的空间来存储变量

        int height; 

}; 

 类的大小

类的大小和结构体的大小计算方式一样,但是类里面的函数并不在类里面,而是在一个叫做公共代码区面,不属于结构体

复习一下结构体的计算方式:

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

class Person
{

public:
	void add();
private:
	int _age;
	int _height;
};

int main()
{
	Person person;
	cout << "sizeof(person)->"<<sizeof(person) << endl;
	cout << "sizeof(Person)->" << sizeof(Person) << endl;
	return 0;
}

运行结果

class Person
{

public:
	void add();

};

int main()
{
	
	cout << "sizeof(Person)->" << sizeof(Person) << endl;
	return 0;
}

运行结果:1
原因:为什么会是1,不是0,因为如果是0的话就相当于什么也没有,是1的话至少能说明有这个东西

由上面的结果说明函数并不是在类里面

class Person
{


};

int main()
{
	
	cout << "sizeof(Person)->" << sizeof(Person) << endl;
	return 0;
}



//运行结果:1
//分析:和上面的一样

从上面的结果来看,在计算类的大小的时候,自看成员变量,不看函数的,因为如果没创建一个对象,里面的函数都在里面,就显得非常浪费空间,就像每家每户都要安装一个游泳池一样,为什么不安装一个公共的嘞

this指针

this指针的引出

有下面的这一段程序

class Date
{

public:
	void print(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date date1;
	date1.print(2024, 8, 13);

	Date date2;
	date2.print(2024, 8, 14);
	return 0;
}

运行结果

上面我们说到,类里面的函数是存储到公共代码区里面的,也就是说上面两个对象(date1,date2)的打印函数用的是同一个函数,从下面的反汇编也可以看出来call函数的地址都是同一个

那为什么函数打印的结果不一样,其实,这里的原因就是由于隐含的this指针

this指针的特性

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2. 只能在“成员函数”的内部使用
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给
this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
递,不需要用户传递

 再来看,其实上面的代码实际上是下面的

class Date
{

public:
    //void print(Date*const this)
	void print(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;
		cout << _year << "-" << _month << "-" << _day << endl;
        //	cout << this->_year << "-" <<this-> _month << "-" <<this-> _day << endl;
}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date date1;
    //date1.print(&date1)
	date1.print(2024, 8, 13);

	Date date2;
    //date2.print(&date2)
	date2.print(2024, 8, 14);
	return 0;
}

两道题

第一道

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
clss A
{
public:
        void Print()
        {
        cout << "Print()" << endl;
        }
private:
        int _a;
};


int main()
{
        A* p = nullptr;
        p->Print();
        return 0;
}

答案选C,运行正常

理由:P->print()里面传的是P,虽然P是空指针,但是形参是空指针没有毛病,而且print()函数不在类里面,P->print()实际上是把P当成形参

class A
{
public:
          void PrintA()
         {
            cout<<_a<<endl;
         }
private:
        int _a;
};
int main()
{
          A* p = nullptr;
          p->PrintA();
          return 0;
}

答案运行崩溃

理由:这里传的也是this指针,但是_a是在类里里面,P又是空指针,所以对空指针解引用运行崩溃

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值