C++编程基础——new/delete与malloc/free区别、运算符重载等

new/delete 和malloc/free 的区别

共同点:

功能相同,new 和malloc 都是在堆区申请指定大小的内存空间,delete 和 free 都是释放指定的一块堆区内存空间(内部实现细节不同,不要混用)。

不同点:

new 和 delete 是 C++中新增的运算符,而malloc 和 free 是函数,所以运算符的执行效率比函数高(对于非对象数据)。

对于非对象数据,它们基本没有区别。

对于对象数据:

  1. 使用 new 运算符在堆区给对象申请空间后,还会调用对像的某个匹配的构造函数,而malloc 函数仅仅就是给对象申请堆区空间,并不会调用其构造函数。
  2. 使用 delete 运算符释放对象时,它首先会调用一次该对象的析构函数,然后再释放对象所占的堆区空间,而 free 函数是直接释放对象所占的堆区空间,并不会调用对象的析构函数。

运算符重载(Operator Overload)

重新定义运算符的功能(面向对象)。

运算符重载函数也是类中的特殊方法,其方法必须"operator 运算符"这种形式。

运算符重载函数既可以为成员函数,也可以为全局函数,建议尽量使用成员函数。

每个类中都有一个默认的赋值运算符重载函数,它实现的是浅拷贝效果,如果不能满足需求,我们可以自己重载它,

五个不可重载的运算符:

  1. .(成员运算符),通常用于访问对象的成员
  2. ::(作用域运算符)
  3. .*(成员指针运算符),即成员是指针类型,访问指针类型成员指向的数据。
  4. ?: (条件运算符)
  5. sizeof(求长度运算符)

仿函数(Functor):重载小括号运算符,所有对象可以像函数调用一样的形式使用。

设计思想:高类聚、低耦合

  • 高类聚是指一个模块内部各个元素之间关系紧密,争取用最少的元素和方法实现相应的功能。
  • 低耦合是指一个程序中各个模块之间的联系少和相互依赖程度低

友元(Friend)

在一个类的友元中可以访问该类的所有成员,如同本类中一样。

友元分为两种:

  • 友元函数
  • 友元类

临时无名对象

生命周期很短,昙花一现,定义它的语句执行完毕就被释放了。

对象类型转换问题

explicit 关键字:用于修饰构造函数(主要是那些带一个参数的构造函数),表示必须显式调用该构造函数,不会被隐式调用;

带一个参数的构造函数可以用于类型转换,即将其他类型数据转型为对象。

通过重载类型转换运算符(类型转换函数)可以实现将对象转型为其他类型。

隐式调用:类名 p =5; //此时这个5作为一个临时无名的对象,被创建赋给p,然后立马被释放。

显式调用:利用 explicit 关键字修饰改造函数,在定义对象时,必须严格按照构造函数参数列表来写

  1. 类名 p {5};
  2. 类名 p (5);

注:一般情况下,出现在带一个参数的构造函数中,使编译器选择为难。

实例一:malloc/free-new/delete

#include <iostream>
#include <cstring>
using namespace std;

class Person
{
private:
    int p_sno = 0;
    char* p_name = nullptr;
public:
    Person()
    {
        p_name = new char[20];
        p_name[0]= '\0';
    }
    Person(int sno,const char* name):p_sno(sno)
    {
        name = new char[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 = new char[20];
        // p_sno = p.p_sno;
        memcpy(&p_sno,&(p.p_sno),sizeof(p_sno));
        memcpy(p_name,p.p_name,20); 
    }

    //重载 赋值 = 运算符
    Person& operator=(const Person& p)
    {
        memcpy(p_name,p.p_name,20);
        p_sno = p.p_sno;
        return *this;
    }



    ~Person()
    {
        cout << p_name << "快死了" << endl;
        // delete 内部实现:
        // 先调用析构函数,等析构函数返回后,才会释放。
        // delete this;此时会无限递归,导致栈溢出。
        delete[] p_name;    //p_name为数组
    }
};

void show1(Person p);   //传对象
void show2(Person& p);  //传对象引用
Person create();
int main()
{   

    // molloc与free属于函数,new/delete 属于运算符
    // Person* p1 = (Person*)malloc(sizeof(Person));

    // p1->show();
    // free(p1);

    //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;相当于创建了一个布局的对象,浪费资源,时间
    p.show();
}

void show2(Person& p)
{
    p.show();
}

Person create()
{
    Person p(1002,"李四");
    cout << &p << endl;
    return p;
}

实例二:友元

#include <iostream>
using namespace std;

class B;

class A
{
private:
    int a;

    void show_a()
    {
        cout << a << endl;

        B* b;
    }

    // 将 B 类声明为当前类的友元类
    friend class B;
};

class B
{
public:
    void show_b()
    {
        A a;
        a.a = 3;
        a.show_a();
    }
};

int main()
{
    B b;

    b.show_b();

    return 0;
}

实例三:重载操作符

#include <iostream>
#include <cstring>

using namespace std;

class Student
{
private:
    int sno;
    string name;
public:
    Student():sno(0),name("")
    {
    }

    Student(int sno,string name):sno(sno), name(name)
    {
    }

    explicit Student(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 &s){
        return 3.14;
    }
    bool operator<(const Student& s)
    {
        return sno < s.sno;
    }

    bool operator>=(int i)
    {
        return sno >= i;
    }

    //  单目运算符
    //  前后置运算符对于非对象的操作效率一样
    //  对于对象,前置运算符效率高一些,后置低一些。
    //  重载前置++p,p为对象;
    Student& operator++()
    {
        sno++;
        return *this;
    }

    //  重载后置p++
    Student operator++(int) //参数写一个int,编译器认为是后置,此参数为 “哑元” 参数
    {
        Student tmp = *this;
        sno++;
        return tmp;
    }

    //  重载下标运算符
    char operator[](int i)
    {
        return name[i];
    }

    //  重载下标运算符:实现名字判断
    string operator[](const char* i)
    {
        if(strcmp(i,"name") == 0) return name;
        else return "error";
    }


    //  重载(强制)类型转换运算符
    operator int()
    {
        return sno;
    }

    //  重载加法运算符
    Student operator+(const Student& s)
    {
        Student tmp;
        tmp.sno = sno + s.sno;
        tmp.name = name + s.name;
        return tmp;
    }
        // 重载括号运算符
    int operator()(int i, int j)
    {
        return 5;
    }

    //  声明友元函数
    friend istream& operator>>(istream& in,Student &s);
    friend ostream& operator<<(ostream& out, const Student& s);

};

//  重载 比较运算符的定义
bool Student::operator >(int i)       //> 属于双目运算符,左操作数为对象,右操作数为传入的
{
        return sno > i;
}

// 重载 
bool operator>=(int i,const Student& s) //全局
{
    return i >= s.getSno();
}
//使用运算符时没有指定,先在类中找符合项,没有找到再去全局区

istream& operator>>(istream& in, Student& s)
{
    cout << "学号:";
    // int sno;
    // in >> sno;          
    // //法一:setSno()传递,不太靠谱
    in >> s.sno;     //法二:友元函数
    cout << "姓名:";
    in >> s.name;
    return in;
}

ostream& operator<<(ostream& out, const Student& s)
{
    out << s.sno << ' ' << s.name <<endl;
    return out;
}



int main()
{
    // // (++p1).show();
    // // (p1++).show();

    // // p1.show();

    // // 100 >= p2;  // operator>=(100, p2);

    // // p2 >= 100;  // p2.operator>=(100);  operator>=(p2, 100);

    // // // p1 = p2;

    // // double d = (p1 > p2);  // double d = (p1.operator>(p2));
    // // cout << d << endl;
    
    // // if(p1 < p2)  // if(p1.operator<(p2))
    // // {
    // //     cout << "yes" << endl;
    // // }

    // // p1 > 1000;  // p1.operator(1000);


    // Student p1,p2;
    // p1 = p2;
    // if(p1 > p2)     //if(p1.operator<(p2))
    // {
    //     cout << "yes" << endl;
    // }

    // p1 + p2;
    // p1 - p2;
    // p1 > p2;
    // p1 && p2;
    // p1[3];
    // int i = int(p1);


    Student s2(3);  // Student s2(3);
    s2 = Student(5);

    // 仿函数(Functor)
    cout << s2(10, 9) << endl;  // 括号运算符

    // 临时无名对象,生命周期很短
    // Student(1001, "李四").show();

    Student p1(1001,"zhangsan"),p2 {1002,"lisi"};
    
    cout << p1 << endl;         //先判断 << 是否有重载方法,再判断 p1是否有重载方法(类型转换)

    // cout << (int)(p1) <<endl;    //
    // cout << int(p2) << endl;

    // cout << p2["name"] << endl;
    
    // cout << p1[2] <<endl; //指定位输出
    

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值