共同点:
功能相同,new 和malloc 都是在堆区申请指定大小的内存空间,delete 和 free 都是释放指定的一块堆区内存空间(内部实现细节不同,不要混用)。
不同点:
new 和 delete 是 C++中新增的运算符,而malloc 和 free 是函数,所以运算符的执行效率比函数高(对于非对象数据)。
对于非对象数据,它们基本没有区别。
对于对象数据:
- 使用 new 运算符在堆区给对象申请空间后,还会调用对像的某个匹配的构造函数,而malloc 函数仅仅就是给对象申请堆区空间,并不会调用其构造函数。
- 使用 delete 运算符释放对象时,它首先会调用一次该对象的析构函数,然后再释放对象所占的堆区空间,而 free 函数是直接释放对象所占的堆区空间,并不会调用对象的析构函数。
重新定义运算符的功能(面向对象)。
运算符重载函数也是类中的特殊方法,其方法必须"operator 运算符"这种形式。
运算符重载函数既可以为成员函数,也可以为全局函数,建议尽量使用成员函数。
每个类中都有一个默认的赋值运算符重载函数,它实现的是浅拷贝效果,如果不能满足需求,我们可以自己重载它,
五个不可重载的运算符:
- .(成员运算符),通常用于访问对象的成员
- ::(作用域运算符)
- .*(成员指针运算符),即成员是指针类型,访问指针类型成员指向的数据。
- ?: (条件运算符)
- sizeof(求长度运算符)
仿函数(Functor):重载小括号运算符,所有对象可以像函数调用一样的形式使用。
设计思想:高类聚、低耦合
- 高类聚是指一个模块内部各个元素之间关系紧密,争取用最少的元素和方法实现相应的功能。
- 低耦合是指一个程序中各个模块之间的联系少和相互依赖程度低
在一个类的友元中可以访问该类的所有成员,如同本类中一样。
友元分为两种:
- 友元函数
- 友元类
生命周期很短,昙花一现,定义它的语句执行完毕就被释放了。
explicit 关键字:用于修饰构造函数(主要是那些带一个参数的构造函数),表示必须显式调用该构造函数,不会被隐式调用;
带一个参数的构造函数可以用于类型转换,即将其他类型数据转型为对象。
通过重载类型转换运算符(类型转换函数)可以实现将对象转型为其他类型。
隐式调用:类名 p =5; //此时这个5作为一个临时无名的对象,被创建赋给p,然后立马被释放。
显式调用:利用 explicit 关键字修饰改造函数,在定义对象时,必须严格按照构造函数参数列表来写
- 类名 p {5};
- 类名 p (5);
注:一般情况下,出现在带一个参数的构造函数中,使编译器选择为难。
实例一:malloc/free-new/delete
#include
#include
using namespace std;
class Person
{
private:
int p_sno = 0;
char* p_name = nullptr;
public:
Person()
{
p_name = new char[20];
p_name[0]= ';'}
Person
(int, snoconstchar *) name:p_sno()sno=
{
name char new [20];strcpy
(,p_name)name;}
void
show (void)const <<
{
cout << p_sno " " << << p_name ; endl}
//拷贝构造函数
Person
(const& Person )p//引用 // 浅拷贝:直接将对象属性的值赋给新对象的属性
{
// memcpy(&p_sno,&(p.p_sno),sizeof(p_sno));
// memcpy(&p_name,&(p.p_name),sizeof(p_sno));
// memcpy(this, &p, sizeof(p));
// 深拷贝:如果属性为指针,则将指针指向空间的内容赋给新对象指针空间的内容
=
p_name char new [20];// p_sno = p.p_sno;
memcpy
(&,p_sno&(.p)p_sno,sizeof()p_sno);memcpy
(,p_name.p,p_name20);}
//重载 赋值 = 运算符
&
Person= operator(const& Person) pmemcpy
{
(,p_name.p,p_name20);=
p_sno . p;p_snoreturn
* ;this}
~
Person()<<
{
cout << p_name "快死了" << ; endl// delete 内部实现:
[
// 先调用析构函数,等析构函数返回后,才会释放。
// delete this;此时会无限递归,导致栈溢出。
delete]; p_name//p_name为数组 }
}
;void
show1 ()Person p;//传对象 void
show2 (&Person) p;//传对象引用 create
Person ();int
main ()// molloc与free属于函数,new/delete 属于运算符
{
// Person* p1 = (Person*)malloc(sizeof(Person));
// free(p1);
// p1->show();
//Person p(1001,"zz");
// //show1(p);
// show2(p);
// Person p = create();
// cout << &p << endl;
;
Person p1//Person p2 = p1; //创建P2用拷贝构造函数等效于:Person p2 {p1}
;
Person p2=
p1 ; p2//调用无参构造函数 // cout << &p1 << endl;
// cout << &p2 << endl;
return
0 ;}
void
show1 ()Person p// 内部实现:Person p = p1;相当于创建了一个布局的对象,浪费资源,时间
{
.
pshow();}
void
show2 (&Person) p.
{
pshow();}
create
Person ()p
{
Person (1002,"李四");<<
cout & <<p ; endlreturn
; p}
#
实例二:友元
include;
using namespace std;
class B:
class A
{
privateint
; avoid
show_a ()<<
{
cout << a ; endl*
B; b}
// 将 B 类声明为当前类的友元类
;
friend class B}
;:
class B
{
publicvoid
show_b ();
{
A a.
a=a 3 ;.
ashow_a();}
}
;int
main ();
{
B b.
bshow_b();return
0 ;}
#
实例三:重载 *** 作符
include#
include;
using namespace std:
class Student
{
privateint
; sno;
string name:
publicStudent
():sno(0),name("")}
{
Student
(int, sno)string name:sno()sno,name ()name}
{
Student
explicit (int) sno:sno()sno,name ("匿名")<<
{
cout "Student(int)" << ; endl}
~
Student()<<
{
cout << sno ' ' << << name " ~Student()" << ; endl}
void
show ()const <<
{
cout << sno ' ' << << name ; endl}
int
getSno ()const return
{
; sno}
//运算符重载(Operator Overload)
(
// 重载比较(>)运算符 //左 *** 作数只能为类、结构体、共用体
bool operator >int) i;double //> 属于双目运算符,右 *** 作数为传入的参数
( operator >const& Student )sreturn{
3.14 ;}
<
bool operator(const& Student) sreturn
{
< sno . s;sno}
(
bool operator>=int) ireturn
{
; sno >= i}
// 单目运算符
// 前后置运算符对于非对象的 *** 作效率一样
// 重载前置++p,p为对象;
// 对于对象,前置运算符效率高一些,后置低一些。
&
Student++ operator()++
{
sno;return
* ;this}
// 重载后置p++
++
Student operator(int)//参数写一个int,编译器认为是后置,此参数为 “哑元” 参数 =
{
Student tmp * ;this++
sno;return
; tmp}
// 重载下标运算符
char
[ operator](int) ireturn
{
[ name]i;}
// 重载下标运算符:实现名字判断
[
string operator](constchar *) iif
{
(strcmp(,i"name")== 0 )return ; nameelse
return "error" ;}
// 重载(强制)类型转换运算符
int
operator ()return
{
; sno}
// 重载加法运算符
+
Student operator(const& Student) s;
{
Student tmp.
tmp=sno + sno . s;sno.
tmp=name + name . s;namereturn
; tmp}
// 重载括号运算符
int
operator ()(int, iint ) jreturn
{
5 ;}
// 声明友元函数
&
friend istream( operator>>&istream, in&Student )s;&
friend ostream<< operator(&ostream, outconst & Student) s;}
;// 重载 比较运算符的定义
::
bool Student(operator >int) ireturn //> 属于双目运算符,左 *** 作数为对象,右 *** 作数为传入的
{
; sno > i}
// 重载
(
bool operator>=int, iconst& Student) s//全局 return
{
. i >= sgetSno();}
//使用运算符时没有指定,先在类中找符合项,没有找到再去全局区
&
istream( operator>>&istream, in& Student) s<<
{
cout "学号:" ;// int sno;
// //法一:setSno()传递,不太靠谱
// in >> sno;
.
in >> s;sno//法二:友元函数 <<
cout "姓名:" ;.
in >> s;namereturn
; in}
&
ostream<< operator(&ostream, outconst & Student) s<<
{
out . s<<sno ' ' << . s<<name ;endlreturn
; out}
int
main ()// // (++p1).show();
{
// // (p1++).show();
// // p1.show();
// // // p1 = p2;
// // 100 >= p2; // operator>=(100, p2);
// // p2 >= 100; // p2.operator>=(100); operator>=(p2, 100);
// // cout << d << endl;
// // double d = (p1 > p2); // double d = (p1.operator>(p2));
// // if(p1 < p2) // if(p1.operator<(p2))
// // cout << "yes" << endl;
// // {
// // }
// Student p1,p2;
// // p1 > 1000; // p1.operator(1000);
// p1 = p2;
// cout << "yes" << endl;
// if(p1 > p2) //if(p1.operator<(p2))
// {
// }
// p1 + p2;
// p1 - p2;
// p1 && p2;
// p1 > p2;
// p1[3];
// int i = int(p1);
s2
Student (3);// Student s2(3); =
s2 Student (5);// 仿函数(Functor)
<<
cout s2 (10,9 )<< ; endl// 括号运算符 // 临时无名对象,生命周期很短
// Student(1001, "李四").show();
p1
Student (1001,"zhangsan"),1002p2 {,"lisi"};<<
cout << p1 ; endl//先判断 << 是否有重载方法,再判断 p1是否有重载方法(类型转换) // cout << (int)(p1) <
// cout << int(p2) << endl;
// cout << p2["name"] << endl;
// cout << p1[2] <
return
0 ;}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)