c++类和对象(上)

类是c++的独特形式,可以在类中包括函数进行。

对象是通过类创建的一个个变量。

类的存储

类中的每一个

类中的函数,不存入类的内存。如图定义了一个类,有一个int类型,4字节。一个函数无内存。

类的存储的大小还要看对齐数

对齐数=(对齐数默认的数)和(类内的成员变量的大小)的较小值,每一个类成员都有一个对齐数。

内存大小为(成员变量的对齐数最大值)的整数倍

vs(对齐数)默认是8

如果是类嵌套,取嵌套中的最大对齐数。

原因1:平台问题,有些硬件平台只能取特定类型的数据。cpu不能从任意位置开始读只能从整数倍开始,不能读任意字节只能读固定字节。如下图4的整数倍开始读,一次性读取4字节。

2:性能原因,处理器处理未对齐的需要两次,对齐的只需要1次。

如果定义的类没有内容,内存为1字节证明存在。成员变量没有内容也会给1字节证明有这个成员。

c++,定义了一个this指针作为。隐藏在类中的函数的一个参数,指向自身,不可修改。

复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
		int a;
	//void print(jst* const this)
	void print( ){
		cout<<a<<endl;
	}
}; 
class st1{
	
};
class st2{
	st1 a;
	st1 b;
};
int main(){
    jst s;
    s.a=10;
    s.print();
    //s.print(&s);
    cout<<sizeof(st1)<<endl;
    cout<<sizeof(st2)<<endl;
    return 0;
}

类中直接访问用.,通过指针访问用->。

不能自己显示的写this指针。

可以在函数体内可以用。

this指针存储到栈中。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
	void print(){
		cout<<"666"<<endl;
	}
}; 
int main(){
    jst* s=nullptr;
    s->print();
    return 0;
}

可以正常运行,因为函数没有存在类中,调用后只传了s的地址。

在c++的类中,可以把不同的数据封装到不同的区,防止胡乱调用。如下面的代码,只能通过jst中的函数进行操作。实现不能直接操作s.a,必须间接操作。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
	void push(int n,int m){
		a[n]=m;
	}
	void print(int n){
		cout<<a[n];
	}
	private:
	int a[4]; 
}; 
int main(){
    jst s;
    s.push(0,1);
    s.print(0);
    return 0;
}

默认成员函数

在类中如果你没有创建,编译器自动生成的函数,还有两个移动构造,移动赋值。

初始化和清理。构造函数初始化工作。

析构函数清理工作。

拷贝复制, 拷贝构造是使用同类对象初始化创建对象。

赋值重载,把一个对象赋值给另一个对象。

取地址重载 普通对象和const对象的取址

构造函数

函数名和类名相同。

无返回值。不需要写void。

对象创建时自动调用。

构造函数可以重载。

无参

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
	jst(){
		a[0]=1;
		a[1]=2;
		a[2]=3;
		a[3]=4;
	}
	void print(){
		cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3];
	}
	private:
	int a[4]; 
}; 
int main(){
    jst s;
    s.print();
    return 0;
}

带参,在创建时跟在创建末尾。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
	jst(int q,int w,int e,int r){
		a[0]=q;
		a[1]=w;
		a[2]=e;
		a[3]=r;
	}
	void print(){
		cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3];
	}
	private:
	int a[4]; 
}; 
int main(){
    jst s(2,3,4,5);
    s.print();
    return 0;
}

全缺省。可以自己初始。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
	jst(int q=1,int w=2,int e=3,int r=4){
		a[0]=q;
		a[1]=w;
		a[2]=e;
		a[3]=r;
	}
	void print(){
		cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3];
	}
	private:
	int a[4]; 
}; 
int main(){
    jst s(0,0);
    s.print();
    return 0;
}

默认构造是不用传参的就是默认构造,包括无参和全缺省。

默认生成2个中的一个.

3个构造函数只能存在一个。

看编译器生成无参函数和全缺省函数。

对于自定义的类型会调用自定义的构造函数。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
class jst{
	public:
		jst(){
			a[0]=1;a[1]=2;a[2]=3;a[3]=4;
		}
	void print(){
		cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;
	}
	private:
	int a[4]; 
}; 
class jst2{
	public:
		void print(){
		a1.print();
		a2.print();
	}
	private:
	jst a1;
	jst a2; 	
};
int main(){
    jst2 s;
    s.print();
    return 0;
}

一般构造函数自己写。

析构函数

析构函数名是在类名前加上字符~;

无参无返回值。

一个类只有一个析构。

对象结束会自动调用。

如果不写会自动生成。

对于自定义,也会调用它的析构。

cpp 复制代码
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
class jst{
	public:
		jst(){
			a=(int*)malloc(sizeof(int)*4);
			a[0]=1;a[1]=2;a[2]=3;a[3]=4;
		}
		~jst(){
			cout<<"0"<<endl;
			free(a);
		}
	void print(){
		cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;
	}
	private:
	int* a; 
}; 
class jst1{
	public:
		jst1(){
			a=(int*)malloc(sizeof(int)*4);
			a[0]=1;a[1]=2;a[2]=3;a[3]=4;
		}
		~jst1(){
			cout<<"1"<<endl;
			free(a);
		}
	void print(){
		cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;
	}
	private:
	int* a; 
}; 
class jst2{
	public:
		void print(){
		a1.print();
		a2.print();
	}
	private:
	jst a1;
	jst1 a2; 	
};
int main(){
    jst2 s;
    s.print();
    return 0;
}

后定义的先析构。

对于自定义函数总会使用自定义的析构。

没有申请资源的类可以不写析构。

显示写析构,也会自动调用默认析构。

运算符重载

运算符在类中可以重载。

cpp 复制代码
#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
class Data{
	public:
		Data(int year=1,int yue=1,int day=1 ){
			_year=year;
			_yue=yue;
			_day=day;
		}
		int que(int n){
			if(n>0&&n<4){
				if(n==1)
					return _year;
				else if(n==2)
					return _yue;
				else
					return _day;
			}
		}
	private: 
	int _year;int _yue;int _day;
};
bool operator==(Data d1,Data d2){
	return d1.que(1)==d2.que(1)&&\
		   d1.que(2)==d2.que(2)&&\
		   d1.que(3)==d2.que(3);
};
int main(){
	Data t1(2,2,2);
	Data t2;
	Data t3;
	if(t1==t2)
		cout<<"666"<<endl;
	else
		cout<<"999"<<endl;
	if(t3==t2)
		cout<<"666"<<endl;	
	return 0;
}
或者
class Data{
	public:
		Data(int year=1,int yue=1,int day=1 ){
			_year=year;
			_yue=yue;
			_day=day;
		}
		int que(int n){
			if(n>0&&n<4){
				if(n==1)
					return _year;
				else if(n==2)
					return _yue;
				else
					return _day;
			}
		}
		bool operator==(Data d2){
		return _year==d2._year&&\
			   _yue==d2._yue&&\
			   _day==d2._day;
		};
	private: 
	int _year;int _yue;int _day;
};

第二种方式使用的this指针,t1.opertaor==(t2),可以省略为t1==t2。

只能对于已有的操作符重载,不能重新创建一个全新的操作符。

相关推荐
doupoa4 小时前
内存指针是什么?为什么指针还要有偏移量?
android·c++
冉佳驹4 小时前
C++ ——— 异常处理的核心机制和智能指针管理
c++·异常捕获·异常继承体与多态·重载抛异常·raii思想·智能指针shared_ptr·weak_ptr指针
C++ 老炮儿的技术栈4 小时前
Qt 编写 TcpClient 程序 详细步骤
c语言·开发语言·数据库·c++·qt·算法
yuuki2332334 小时前
【C++】继承
开发语言·c++·windows
梵刹古音5 小时前
【C++】 析构函数
开发语言·c++
wangjialelele5 小时前
Linux下的IO操作以及ext系列文件系统
linux·运维·服务器·c语言·c++·个人开发
打工哪有不疯的5 小时前
使用 MSYS2 为 Qt (MinGW 32/64位) 完美配置 OpenSSL
c++·qt
代码游侠5 小时前
C语言核心概念复习——C语言基础阶段
linux·开发语言·c++·学习
㓗冽5 小时前
60题之内难题分析
开发语言·c++·算法
rainbow68896 小时前
C++开源库dxflib解析DXF文件实战
开发语言·c++·开源