本帖最后由 gwgirl 于 2022-1-16 18:23 编辑
运行环境:
如 WIN10
涉及工具:
VS2022
编程语言:
C/C++
以下为主题内容:希望对学习C++的新手有所帮助
面向对象和面向过程最本质的三个区别:封装 继承 多态
想要学好C++没有C的基础是不可能学好C++的,C++并不会超越我们学的C的语法,用我们学的C的知识,全部都可以解决,那么C是容易学的语言,那C++还难吗?学好了C再用C++你会觉得是一种享受;
C++本身就是在C的基础上做了一些拓展,编译器帮我们生成了一些代码,当你知道C++帮我生成了哪些代码,你的C++就学完了;C++并不难学,大家不需要对C++想象的那么复杂.
????????????1.什么是封装:
把函数定义到结构体里面的写法就是封装,封装的好处就是这个函数可以很方便的访问结构体里面其他的成员;
struct Base
{
int x;
int y;
};
int Sub(Base* p)
{
return p->x - p->y;
}
int main()
{
Base T;
Sub(&T);
}
函数写到结构体里面和外面又有什么区别呢?
普通函数使用结构体成员我们需要传参,就像下面这段代码一样,如果写入到结构体里面,
我们就不需要去手动传参,编译器会替我们把当前结构体的地址(通过寄存器ECX)传到函数当中;
struct Base
{
int x;
int y;
int Sub()
{
return x-y;
}
};
int main()
{
Base T;
T.Sub();
}
????????????2.什么是类:
带有函数的结构体,称为类,我们把struct 换成 class;
class Base
{
int x;
int y;
int Sub()
{
return x-y;
}
};
????????????3.什么是成员函数:
结构体里面的函数,称为成员函数;
struct Base
{
int x;
int y; //这个是成员
int Sub() //这个就是成员函数
{
return x-y;
}
};
???????????? this 指针的作用 ????????????????
????只要我们把函数写到结构体里面,编译器就会替我们把当前结构体的地址;
(通过寄存器ECX)传到函数当中,
????而传的这个地址,也就是指针就是this指针,this指针不占结构体宽度;
????虽然你定义的时候函数是空的,但是这个指针任然存在;
struct Base
{
int x;
int y;
void Sub(){ }
};
???? 用开区分哪个是参数,哪个是成员 this指针不可以进行运算,不允许重新赋值
struct sclass
{
int a;
int b;
void init(int a,int b)
{
a=a; //这样写编译器分不清这两个a谁是谁,相当于自己的值赋给了自己;
this->a=a; //我们想要把值赋给结构体的a需要用this指针告诉编译器;
this->b=b; //this这个指针是编译器自己为我们创建的,我们不需要自己创建
}
void Print()
{
printf("%d %d",a,b);
}
};
???? 返回当前对象的首地址;
int GetAddr()
{
return *(int*)this;
}
-------------???????????????????????? 构造函数的定义 ????????????????????????-------------
构造函数的特点:希望给我的成员赋值就使用,不希望就不使用(初始化使用)
1、于类同名 构造函数会被编译器默认自动执行和调用
struct sclass
{
int a;
int b;
sclass()
{
a = 1;
b = 2;
printf("我们没有调用这个函数他为什么执行了呢?这就是构造函数的特性\n");
}
};
int main()
{
sclass T;
printf("%d %d", T.a, T.b);
return 0;
}
2、没有返回值
3、创建对象的时候执行
4、主要用于初始化,你希望在你当前的对象创建的时候做什么事,你就把你的逻辑功能写在构造函数里
5、可以有多个(最好有一个无参数的),称为重载,其他函数也可以重载,参数可以一样但是个数一定不要一样
以下示例代码大家复制测试:
struct sclass1
{
int a;
int b;
sclass1()
{
printf("无参数构造函数\n");
}
sclass1(int a,int b)
{
this->a = a;
this->b = b;
printf("有参数构造函数\n");
}
sclass1(int a, int b,int c)
{
this->a = a;
this->b = b+c;
printf("有参数构造函数\n"); //这三个函数之间的关系就是重载关系
}
};
int main()
{
sclass1 T; //我们写无参的编译器就给我们调用无参数的
sclass1 S(1, 2); //我们需要有参的编译器就给我们调用有参数的
sclass1 D(1, 2,3); //主要我们用起来是不是很方便
printf("%d %d\n", S.a, S.b);
printf("%d %d\n", D.a, D.b);
return 0;
}
6、编译器不要求必须提供,但是写了编译器就会自动调用哦个
[C] 纯文本查看 复制代码 struct Person
{
int age;
int level;
//构造函数->给我们的成员赋值
Person(int age,int level)
{
this->age=age;
this->level=level;
}
//重载函数->我们在给个空函数用的时候就可以不传参数
Person()
{
printf("%d %d",age,level);
}
void print()//成员函数
{
printf("%d %d",age,level);
}
void print(int x)//成员函数也可以重载 参数或类型不一样就可以
{
printf("%d %d",age,level);
}
};
int main()
{
Person p(1,2);//先创建对象,有构造函数的时候就必须得用,给他传参数进去
P.print();//创建出来通过对象的方式使用成员函数
return 0;
}
-------------???????????????????????? 析构函数的定义 ????????????????????????-------------
析构函数:是给我用来做清理工作(首位的时候使用)
1、于类同名 在前面加一个波浪线 ~
2、没有返回值
3、析构函数不需要我们调用,系统替我们调用,编译器替我们生成的调用代码
4、临时变量我们不需要使用析构函数去处理
5、析构函数不允许重载,第一。没必要,第二、重载的时候第一次已经释放,那这次释放谁?
6、编译器不要求必须提供,但是写了就会自动使用,没必要的时候不要随便加;
[C] 纯文本查看 复制代码 struct Person
{
int age;
int level;
//构造函数->给我们的成员赋值
Person(int age,int level)
{
this->age=age;
this->level=level;
arr = (char*)malloc(1024);//这里我申请了空间需要释放
}
Person()//重载函数
{
printf("%d %d",age,level);
}
~Person()//析构函数
{
//写个析构函数,系统就帮我们在使用完对象后释放了空间
//不需要我们手动释放空间和调用这个析构函数
}
};
int main()
{
Person p(1,2);//先创建对象,有构造函数的时候就必须得用,给他传参数进去
P.print();//创建出来通过对象的方式使用成员函数
return 0;
}
3.析构函数何时执行呢?
<1>/当对象在堆栈中分配(在main函数里面创建的)
当main函数执行完的时候,在return 0;执行之前,执行调用的析构函数;
int main()
{
Person p(1,2);
return 0;
}
<2>/当对象在全局区分配
当前的应用程序退出之前会调用析构函数;
Person p(1,2);
int main()
{
return 0;
}
-------------???????????????????????? 继承函数的定义 ????????????????????????-------------
继承函数:定义好多个结构,但是好多成员是一样的
我们不想写就可以把他删除掉,用继承去实现
1、继承就是数据的复制
2、为什么要用继承?减少重复代码编写
3、Person1称为父类或基类
4、Teacher、student成为子类或者派生类
5、t和s可以成为对象或者实例
6、可以用父类指针指向子类对象
struct Person1
{
int age;
int sex;
};
struct Teacher
{
int age;
int sex;
int level;
int classID;
};
struct student
{
int age;
int sex;
int code;
int score;
}
void test()
{
Teacher t;
t.age=1;
t.sex=2;
t.level=3;
t.classID=4;
}
int main()
{
test();
return 0;
}
2、为什么要用继承?减少重复代码编写
struct Person1
{
int age;
int sex;
};
struct Teacher:Person1//告诉他我要用他的这些成员
{
int sex;//子类中也有这样的一个成员,继承的时候依然会把父类的这个成员继承过来,我们尽量避免出现这样的情况;
int level;
int classID;
};
struct student:Person1//告诉他我要用他的这些成员
{
int code;
int score;
}
void test()
{
Teacher t;
t.age=1;
t.sex=2;//这里我们赋值的子类成员,想要给父类的这个成员赋值怎么办呢?
t.Person1::sex=3;//这样我们就使用了到了父类的sex;
t.level=4;
t.classID=5;
}
int main()
{
test();
return 0;
}
6、可以用父类指针指向子类对象
struct Person1
{
int age;
int sex;
};
struct Teacher:Person1//告诉他我要用他的这些成员
{
int level;
int classID;
};
void test()
{
Teacher t;
t.age=1;
t.sex=2;
t.level=3;
t.classID=4;
teacher* pt=&t;
printf("%x\n",pt->sex);我用指针指向这个对象t的成员
Person1* pP=&t;
//我也可以用父类创建的指针指向这个对象t继承过来的成员age/sex
//不可以通过父类指针访问子类其他成员
printf("%x\n",pP->sex);
}
int main()
{
test();
return 0;
}
-------------???????????????????????? 多层继承函数 ????????????????????????-------------
继承不仅仅局限于父类,下面这段代码Y继承了X,Z又继承了Y;
Z是只继承了CD呢还是AB也一起被继承过来?
struct X
{
int a;
int b;
};
struct Y:X
{
int c;
int d;
};
struct Z:Y
{
int e;
int f;
};
vodi Test()
{
Z z;
printf("%d",sizeof(z));//Z就继承了X,Y;
}
如果父类与子类之间发生了重复定义,也是可以继承过来的,但是在使用的时候必须明确的表示出来使用的是谁的变量
struct X
{
int a;
int b;
};
struct Y:X
{
int a;
int d;
};
struct Z:Y
{
int e;
int f;
};
vodi Test()
{
Z z;
z.X::a=1; //
z.b=2;
z.Y::a=3;
z.d=4;
z.e=5;
z.f=6;
printf("%d",sizeof(z));//Z就继承了X,Y;
}
-------------???????????????????????? 多重继承函数 ????????????????????????-------------
微软推荐只有一个父类但是C++支持有多个父类
如果出现同名和多层继承一样的使用
struct X
{
int a;
int b;
};
struct Y
{
int c;
int d;
};
struct Z:X:Y
{
int e;
int f;
};
vodi Test()
{
Z z;
printf("%d",sizeof(z));//Z就继承了X,Y;
}
内存结构:
struct Z:X:Y的 顺序决定了 内存结构中谁在上面,谁在下面,这样写结构体的首地址就是a;
struct Z:Y:X的 顺序决定了 内存结构中谁在上面,谁在下面,这样写结构体的首地址就是c;
多重继承增加了程序的复杂度,不建议使用;
?????????????????????????????????????? 如何在堆中创建对象 ??????????????????????????????????????
1.我们可以在什么地方创建对象
<1>全局变量区
Person p;
<2>栈:什么时候调用对象,什么时候分配空间,函数调用完毕之后,这个空间就没有了
void Max()
{
Person p;
}
<3>堆: new delete
在堆中创建对象:
Person* p=new person(); //C++我们申请空间使用NEW这个关键词
释放对象占用的内存:
delete p;
????malloc(N)我们在C语言中想使用空间就可以通过malloc函数,申请的空间就是在堆中分配的
一些书上堆new 和 delete 的描述都很模糊,下面我们看一下new到底做了那些事情;
class person
{
int x;
int y;
public:
person()
{
printf("person()执行了 \n");
}
person(int x, int y)
{
printf("person(int x,int y)执行了 \n")
this->x = x;
this->y = y;
}
~person()
{
printf("~person()执行了\n");
}
};
int main()
{
//在堆中创建对象
person* p = new person(1, 2);
//new 除了创建堆空间以外,还要调用构造函数 ,相当于malloc+构造函数
//new 最终要调用的是HeadAlloc Windows系统函数(不是我们的EXE内部的函数)
//释放对象占用的内存空间
delete p;\
//delete 除了释放堆空间以外,还要调用析构函数 ,相当于free+析构函数
return 0;
}
如果使用的是数组,那就不能使用new了,而需要使用new[ ] 和 delete[ ]
我们分别用C和C++两种方式,在堆中申请一个int类型的数组:
<1>
int* p = (int*)malloc(sizeof(int)*10); free(p);
int* p = new int[10]; delete[ ]p;
<2>
int* p = (Person*)malloc(sizeof(Person)*10); free(p);
Person* p = new Person[10]; delete[ ]p;
????????????????????? 后续继续把虚函数等等都给大家发出来希望对大家有所帮助???????? ?????????????????????
|