类与类的相关
一、类,类的大小,类的封装
1. C语言和C++
C语言: 面向过程的程序设计语言(按照问题解决的步骤,封装函数一步步实现)
C++: 面向对象的程序设计语言(按照问题涉及到的对象去封装类,通过类中的方法去实现最终效果)
例:
动物类: 哺乳动物和两栖动物
动物都具备行为和属性
行为 ---> 方法,函数
吃肉,叫,跑
属性 ---> 变量
年龄,分类,颜色
面向对象编程三大核心思想: 封装,继承,多态
封装: 通过定义类,类中定义方法和属性去把现实生活中的问题抽象为一个个的类
继承: 使用已经存在的类作为基础建立新的类的技术,新的类的定义可以增加新的功能或者新的数据,也可以使用父类的功能但是不能选择性的继承父类。
多态: 指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
2. 类的定义
类理解为程序员自定义的一种数据类型
(一)定义类
语法规则:
class 类的名字(类的名字一般首字符大写)//或者你写成struct 类的名字
{
成员方法;
成员变量;
};
例如:
class Animal
{
void run();
void eat();
int color;
int age;
} ;
(二)定义类的对象并调用成员方法或者成员属性
定义类的对象:
类名 对象名;//类-->理解为就是一种数据类型
调用成员方法或者属性:
第一种:普通对象 对象名.方法
对象名.属性
第二种:对象指针 对象名->方法
对象名->属性
成员方法的定义有两种写法
写法一: 成员方法定义在类的里面(代码量很少)
例:
class Animal
{
//加上权限修饰符
public: //公有的
void run() //成员方法
{
cout<<"动物跑得很快"<<endl;
}
int age; //成员属性
private: //私有
float weight; //体重私有的
};
写法二:成员方法定义在类的外面
例:
class Animal
{
//加上权限修饰符
public: //公有的
void run(); //在类的里面声明函数,函数的源码在类的外面去写
int age; //成员属性
private: //私有
float weight; //体重私有的
};
void Animal::run()// ::称之为类作用域运算符(类的所属符号)
{
cout<<"动物跑得很快"<<endl;
}
(三)类的调用
类的成员函数和成员属性调用
第一种:正常情况下,我们都是通过定义对象,然后对象去调用类的成员方法和成员属性
第二种:类名直接调用成员方法或者成员属性也可以(成员方法和属性都必须是共有的且静态的,static修饰)
3. 类中的权限
作用: 限制程序员对于方法或者属性的使用,起到保护成员方法或者成员属性的目的
总共有三种: 公有public 私有private 保护protected
公有: 类的外面和类的里面都能使用(类内、类的对象;派生类内、派生类对象->均可访问。)
私有: 只能在类的内部使用,其他地方不能使用(类内、派生类内->可以访问;类的对象、派生类的对象->不可访问。)
保护: 只能在类的内部使用(只有类内部->可以访问;类的对象、派生类、派生类的对象,统统的->不可访问。)
注意:如果你定义类的时候没有写任何权限修饰符号,默认全部都是私有的(private)
类的里面: 类定义的时候那对花括号
类的外面: 类定义花括号外面的都是属性类的外部
4. this指针
作用: this指针是一个专门指向当前对象的一个指针
哪个对象调用this,那么this就表示这个对象
例:
int getAge()
{
int age;
this->age=age;//局部变量age赋值本类对象的私有成员age
return this->age;
}
5. 类的大小
类的大小只跟成员属性有关,跟成员函数无关(成员函数存放在内存中的代码段,也称之为方法区)
成员属性只包括非静态成员属性(因为静态成员属性存放在数据段中的)
也要满足字节对齐的要求,跟结构体字节对齐套路一样
空类的大小是多少 ->1个字节
空类:只是定义了名字,里面没有任何内容
class People
{
};
补充:
cout 是输出流类(ostream)的一个对象
cin 是输入流类(istream)的一个对象
string 专门表示字符串的一个类
二、函数带默认参数
在函数带默认参数时,在调用函数时,可以传默认的参数,也可以不传默认的函数;当传参数时,便使用传的参数值;当不传函数时,便使用默认的参数值。
规则:任何函数带默认参数,只能从右到左依次连续默认
例:
void showPic(const char *pathname,int x,int y=100)
void showPic(const char *pathname,int x=250,int y=100)
void showPic(const char *pathname="/1.bmp",int x=250,int y=100)
//以下三种都是错误的,不满足从右到左连续默认
void showPic(const char *pathname="/2.bmp",int x,int y)
void showPic(const char *pathname,int x=250,int y)
void showPic(const char *pathname="/3.bmp",int x,int y=100)
三、构造函数,构造器(重点)
1. 作用
只要新建了对象,构造函数就会自动被调用
构造函数就是为了新建对象而生的
2.语法规则
类名(参数)
{
代码
}
3.特点
①构造函数名字必须跟类的名字一模一样,并且构造函数是没有任何返回值类型的,只能定义成公有成员
②构造函数有很多种重载形式
③程序员没有定义构造函数,系统会自动生成一个无参构造函数,如果程序员定义了无参构造函数,那就使用程序员自定义的构造函数
4.构造函数所有的写法
①无参构造函数
Animal()
②有参数构造函数
Animal(int newage)
Animal(int newage,string newname)
③带默认参数的构造函数(容易跟前面两种起冲突,最好不要第一种,第二种,第三种都写在一起)
Animal(int newage=5,string newname="xiaohuang")
④参数列表形式的构造函数
Animal(int _age,string _name):age(_age),name(_name)
⑤子类构造函数参数列表中指定调用父类的构造函数
子类构造函数(参数):父类构造函数(参数)
{
代码;
}
Dog(int newnum,string newstr):Animal(newnum,newstr)
四、析构函数,析构器
1. 作用
只要对象的地址空间释放了,析构函数就会被自动调用
实际开发中,我们把收尾工作交给析构函数去完成(比如:释放堆空间,关闭文件)
2.语法规则
~类的名字()
{
代码
}
3.特点
①没有任何重载形式,只有一种写法,没有任何参数,固定只有一种写法
②程序员没有定义析构函数,系统会自动生成一个析构函数,如果程序员定义了析构函数,那就使用程序员自定义的析构函数
五、拷贝构造函数,深拷贝和浅拷贝
1. 作用
当你一个对象赋值给另外一个新的对象的时候,就会自动调用拷贝构造函数(给另外对象初始化赋值)
2.语法规则
类名(类的对象引用)
{
代码
}
小结:
Animal a;
Animal b=a;
等价于 Animal b(a);
3. 深拷贝和浅拷贝
总结:
系统默认的拷贝构造函数很局限,遇到申请堆空间,那么所有拷贝得到的对象全部都共享同一个堆空间 -> 这种拷贝称之浅拷贝
深拷贝:我们程序员自己写代码,解决浅拷贝的bug