C++:类与对象(更新中)
参考自身学习的学习经验与Primer c++ 第五版的定义:类的基本思想是数据抽象与封装。 说得简单一些,那就是**:对事物的往上抽象** 称为 类。 具体怎么解释呢,比如,对于我们大家而言,如果将我们抽象出来的话,那就是人。我们可以抽象成人 类。 再比如动物,比如猫,狗,猪,我们可以把他们抽象成为动物类。 正在学校学习的我们可以抽象成学生类。教师们也可以抽象成为 教师类。
1.1:类与对象的基本概念透析:
类的构成有属性、行为之分: (初学C++对这些概念可能不太清楚,如果不仔细斟酌品味,到后面容易混乱)
属性:又被称为 数据 行为:又被称为 函数、方法
属性 与 行为 我们一般统称为 成员 ,所以又可以这样这样写: 属性, 称为: 成员属性、成员变量。 行为, 称为: 成员函数、成员方法
怎么理解属性与行为呢? 比如一个人类:Human 人,应该有他的名字,年龄等等,这些就叫做:属性。 行为呢? 吃喝拉撒 就是人的行为。
那么,啥叫 对象 ?(又称实例化) 再次举例,有了定义人类Human 以后,我们就可以实例化对象。 那么实例化我,又被称为 创建了一个 我 的对象。 然后根据类中的行为(吃喝拉撒)与属性(年龄、姓名),再次进行进一步的赋值。 比如创建了 我 这个对象以后,我名字叫张三。 然后再创建了 你 这个对象 ,你名字叫李四。
1.2:类(class)与对象在C++中代码的体现(Public):
代码如下(部分):
Class Human{
Public:
string name;
int age;
Void eat(){
cout<<"吃"<<endl;
};
Void drink(){
cout<<"喝"<<endl;
};
Void biubiubiu(){
cout<<"拉"<<endl;
};
Void pilipala(){
cout<<"撒"<<endl;
};
}
int main(){
Human Zhangsan
Human Lisi
Zhangsan.name="张三";
Zhangsan.age=18;
Lisi.name="李四";
Lisi.age=19;
cout<<Zhangsan.eat()<<endl;
}
1.3:访问权限
类在设计的时候, 成员属性与成员函数可以放在不同的权限下,用于控制: ①public:公共权限 ②protected:保护权限 ③private:私有权限
区别: public:成员 类内可以访问,类外可以访问 protected:成员 类内可以访问,类外不可访问 子类可以访问 private:成员 类内可以访问,类外不可访问 子类不可以访问
代码如下:
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
string house;
protected:
int money;
void fun_pro();
private:
int bank_password;
void fun_pri();
public:
void test1(){
string house="别墅";
int money=888;
int bank_password=123;
}
};
int main(void){
Human son;
son.house="海景房";
son.test1();
system("pause");
return 0;
}
1.4:结构体struct 与 类class的区别:
其实是一样的,只是有一点区别,那就是在默认的权限不一样. struct:默认权限是公有 class:默认权限是私有
class Human{
int name;
};
struct Human{
int name;
};
1.5:成员属性设为私有的意义
优点1:可以自己控制读写权限(按需定义读写) 优点2:对于写权限,可以检测数据的有效性
代码如下:(部分 代码是从文档写下来然后拷贝过来的,应该有些错误 但不影响)
Class Human{
Private:
String h_name;
Int h_age;
String h_lover
Public:
String getName(){
return h_name;
}
Void setName(string name){
h_name=name;
}
Int getAge(){
Return h_age
}
Void setLover(strng lover){
h_lover=lover
}
}
Public:
Void setAge(int age){
If(age<0 ||age>150){
Return;
}
h_age=age;
};
1.6:构造函数与析构函数
构造函数: 1.没有返回值 不需要void; 2.函数名与类名一致; 3.形式:有参\无参\重载 4.创建对象时,会自动调用且只调用一次.
析构函数: 1.进行堆区清理操作 2.无返回值 不需要void 3.函数名与类型相同 只需要前面加上:~ 4.不能够带参,不可以重载 5.对象销毁前会自动调用析构函数,只调用一次.
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
Human(){
cout<<"无参构造函数的调用"<<endl;
}
Human(int a){
age=a;
cout<<"有参构造函数的调用"<<endl;
}
~Human(){
cout<<"析构!"<<endl;
};
public:
int age;
};
void test01(){
Human wucan;
};
void test02(){
Human youcan(10);
cout<<youcan.age<<endl;
};
int main(void){
test01;
test02();
system("pause");
return 0;
}
1.7:构造函数的分类:
构造函数的分类: ①按参数分: 有参构造 无参构造 ②按类型分: 普通构造 拷贝构造
构造函数的调用方式: ①括号法 ②显示法 ③隐式转换发
无参与有参(代码与上面类似 为了容易区分 分多个区域写):
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
Human(){
cout<<"Human 无参"<<endl;
}
Human(int a){
age=a;
cout<<"Human 有参"<<endl;
}
private:
int age;
};
void test01(){
Human a;
};
void test02(){
Human b(10);
}
int main(void){
test01;
test02();
system("pause");
return 0;
}
拷贝构造函数: 顾名思义 就是用于复制(拷贝)一个对象 的函数
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
Human(int a){
age=a;
cout<<"Human 有参"<<endl;
}
Human(const Human &son){
age=son.age;
cout<<"Human 拷贝"<<endl;
}
public:
int age;
};
void test03(){
Human b(10);
Human son(b);
cout<<b.age<<endl;
cout<<son.age<<endl;
}
int main(void){
test03();
system("pause");
return 0;
}
构造函数调用方法: 随便你用哪个都行 看你喜欢
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
Human(){
cout<<"Human 无参"<<endl;
}
Human(int a){
age=a;
cout<<"Human 有参"<<endl;
}
Human(const Human &son){
age=son.age;
cout<<"Human 拷贝"<<endl;
}
private:
int age;
};
void test_1(){
Human a;
Human b(10);
Human c(b);
cout<<"括号法-------"<<endl;
}
void test_2(){
Human aa;
Human bb=Human(100);
Human cc=Human(bb);
cout<<"显示法-----------"<<endl;
}
void test_3(){
Human bbb=1000;
Human ccc=bbb;
cout<<"隐式转换法-------------"<<endl;
}
int main(void){
test_1();
test_2();
test_3();
system("pause");
return 0;
}
运行图:
1.8: 拷贝构造函数的调用时机
题目理解起来可能有些模糊. 意思就是: 编译器会在什么时候调用 拷贝构造函数
时机①:使用已有的对象用来初始化新的对象 时机②:以值传递的形式给函数参数传值 时机③:以值的方式返回局部对象 时机④ 对象数组的初始化列表中,使用对象
代码如下: 有注释 应该不会看懵
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
int age;
Human(){
cout<<"无参构造函数"<<endl;
}
Human(int a){
age=a;
cout<<"有参构造函数"<<endl;
}
Human (const Human &son){
age=son.age;
cout<<"拷贝构造函数"<<endl;
}
~Human(){
cout<<"析构函数调用"<<endl;
};
};
void test01(){
Human p1(10);
Human p2(p1);
cout<<p1.age<<endl;
cout<<p2.age<<endl;
}
void demo2(Human x){
}
void test02(){
Human q1;
demo2(q1);
}
Human demo3(){
Human a1;
return a1;
}
void test03(){
Human a = demo3();
}
int main(void){
cout<<"调用test01方法:(这是一个最常见的拷贝函数构造调用方法)"<<endl;
test01();
cout<<"----------------------------------------------------------"<<endl;
cout<<"调用test02方法:(以值传递的形式给函数参数传值)"<<endl;
test02();
cout<<"----------------------------------------------------------"<<endl;
cout<<"调用test03方法:(以值的方式返回局部对象)"<<endl;
test03();
system("pause");
return 0;
}
代码实现图:
1.9: 构造函数调用规则:
默认情况下,C++编译器至少会给一个类添加3个构造函数:
①默认构造函数(无参的,函数体为空的) ②默认析构函数(无参的,函数体为空的) ③默认拷贝构造函数,对属性进行值的拷贝.
规则: ①如果定义了有参构造函数,C++不会提供无参构造函数,但是会提供默认构造函数.
②如果定义了拷贝构造函数,C++不会提供其他构造函数了(包括默认构造\默认析构函数\默认拷贝构造函数)
可以理解为:你去一家面馆吃饭,你跟老板说来碗热面. (你没有提要求),老板就会给你热面放香菜进去. 但是如果你提了要求,说来碗热面不要香菜,那老板就不会给你放香菜.
1.10: 浅拷贝与深拷贝:
浅拷贝:简单的赋值拷贝,带来了问题就是 堆区内存的重复释放 深拷贝:在堆区重新new空间,进行拷贝赋值.
伪代码:
Human a1;
human a2(a1);
假设我们在前面给a1这个对象new了一块空间:
int *arrd;
对象a1的这个成员会指向一个地址为:0x0001的堆区
拷贝出来一个a2的时候 ,浅拷贝就是一个完全的赋值拷贝,
对象a2的arrd成员也会指向地址为:0x0001的堆区;
我们知道析构函数会清理操作,
假设析构函数被调用进行清理的时候
那么就会 重复清理某一个堆区(这是非法的)
所以就需要在实现拷贝构造函数的时候,需要自己定义:
Human(const Human &son){
arrd=new int(*son.addr);
}
如果你不为它重新创建一个堆区,系统会默认调用这个代码:
addr=son.addr;
2.1: 初始化列表:
初始化列表: 作用:初始化属性 语法:构造函数():属性1(value1),属性2(value2)…{};
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
class Human{
public:
int p_a;
int p_b;
int p_c;
Human(int a,int b,int c){
p_a=a;
p_b=b;
p_c=c;
}
};
class Super{
public:
int m_a;
int m_b;
int m_c;
Super(int a,int b,int c):m_a(a),m_b(b),m_c(c){};
};
void test01(){
Human s1(10,20,30);
cout<<"---调用有参构造函数(传统调用)---"<<endl;
cout<<s1.p_a<<endl;
cout<<s1.p_b<<endl;
cout<<s1.p_c<<endl;
cout<<endl;
}
void test02(){
Super s2(10,20,30);
cout<<"---调用有参构造函数(初始化列表)---"<<endl;
cout<<s2.m_a<<endl;
cout<<s2.m_b<<endl;
cout<<s2.m_c<<endl;
}
int main(void){
test01();
test02();
system("pause");
return 0;
}
实现图:
2.2: 类对象作为类的成员:
|