面向对象基础-析构函数-this-static-const

2024-01-02 10:15:08

析构函数

析构函数是与构造函数对立的函数。

构造函数

析构函数

创建对象时手动调用

当对象销毁时,自动调用

函数名称与类名相同

函数名称是~类名

构造函数可以重载

析构函数没有参数,不能重载

用于创建对象时并初始化

用于销毁对象时释放资源

“有构造函数返回值”

没有返回值

3.4.3的代码优化为:

#include?<iostream>
#include?<string.h>
using namespace std;
class Dog
{
private:
    char *name;
public:
    Dog(char *n)
    {
????????name?= new char[20];
        strcpy(name,n);
    }

    Dog(Dog?&d)
    {
???????name?= new char[20];
       strcpy(name,d.name);
    }

    void show_name()
    {
????????cout?<<?name?<<?endl;
    }
    //?析构函数,对象销毁时自动调用(花括号结束对象销毁)
    ~Dog()
    {
????????cout?<< "我被调用了" <<?endl;
????????delete?[]name;
????????name?=?NULL;
    }
};
int main()
{
    char?arr[20] = "旺财";
    Dog d1(arr);
    Dog d2(d1); //?拷贝构造函数
    strcpy(arr,"大黄");
????d1.show_name(); //?旺财
????d2.show_name(); //?旺财
    return 0;
}

  1. 作用域限定符“::”

匿名空间:默认空间

名字空间:用户命名

就近原则;

1?名字空间(熟悉)

#include?<iostream>
using namespace std;//匿名空间
int?a?= 2;
namespace?my_space//名字空间
{
    int?a?= 3;
    int?b?= 4;
}
using namespace my_space;//使用名字空间
int main()
{
    int?a?= 1;
????std::cout?<<?a?<<?std::endl;  //?1?就近原则
????std::cout?<< ::a?<<?std::endl; //?::是匿名名字空间。2,匿名空间为空会报错
????cout?<<?my_space::a?<<?endl; //?3?名字空间
????cout?<<?b?<<?endl;  //?4若没有其他匿名或就近,则直接调用唯一空间变量若有其他空间变量,则需要指定空间
    return 0;
}

2?类内声明,类外定义,主函数内调用

#include?<iostream>
using namespace?std;
class Demo
{
public:
    Demo();//构造函数类内声明
    void test(string?str);//类内声明函数
};
//类外实现
Demo::Demo()
{
????cout<<"创建了一个对象"<<endl;
}
//类外实现
void Demo::test(string?str)
{
????cout<<str<<endl;
}
int main()
{
????Demo?d;//创建一个类的对象
????d.test("helloworld?");//调用类内成员函数
    return 0;
}

this指针

1?概念

this指针是一个特殊指针,指向当前类对象的首地址。

成员函数(包括构造函数与析构函数)都有this指针。因此this指针只能在类内使用。实际上this指针指向的就是当前运行的成员函数所绑定的对象。

#include?<iostream>
#include?<string.h>
using namespace std;
class Test
{
private:
    string?name;
public:
    Test(string?name):name(name){}
    void show_this()
    {
????????cout?<< this <<?endl; //?0x61fe84
    }
};
int main()
{
    Test t1("小明");
????cout?<< &t1?<<?endl; //?0x61fe84
????t1.show_this();
????Test?*t2?= new Test("张三");
????cout?<<?t2?<<?endl;
????t2->show_this(); //?0x1327a8
    delete?t2;
????t2?=?NULL;
    return 0;
}

指针地址一致

  • 类中成员的调用都依赖this指针,通常由编译器自动添加。

#include?<iostream>
#include?<string.h>
using namespace std;
class Test
{
private:
    string?name;
public:
    Test(string?name):name(name){}
    void func1()
    {
????????cout?<< "哈哈哈哈" <<?endl;
    }
    void func2()
    {
        //?类内调用成员时,编译器自动添加this指针。
????????cout?<< this->name?<<?endl;
        this->func1();
    }
};
int main()
{
????Test?*t2?= new Test("张三");
????cout?<<?t2?<<?endl;
????t2->func2();
    delete?t2;
????t2?=?NULL;
    return 0;
}

2?功能

  • 区分重名的局部变量与成员变量

#include?<iostream>
using namespace std;
class Test
{
private:
    string?name;
public:
    Test(string?name)
    {
        this->name?=?name;//指示当前类的成员对象
    }

    void test_this()
    {
????????cout?<< this <<?endl; //?0x61fe84
    }
};
int main()
{
    Test t1("小明");
????cout?<< &t1?<<?endl; //?0x61fe84
????t1.test_this();
????Test?*t2?= new Test("张三");
????cout?<<?t2?<<?endl; //?0xf726a8
????t2->test_this();
    return 0;
}

  • 类中成员的调用都依赖于this指针,通常由编译器自动添加。

#include?<iostream>
using namespace std;
class Test
{
private:
    string?name;
public:
    Test(string?name)
    {
        this->name?=?name;
    }
    void func1()
    {
????????cout?<< "哈哈哈哈哈" <<endl;
    }
    void func2()
    {
//????????cout?<<?this->name?<<?endl;?//?this指针编译器帮我们自动添加
//????????this->func1();
    }
};
int main()
{
    Test t1("小明");
????t1.func2();
    return 0;
}

  • 链式调用

支持链式调用的成员函数特点:

  1. 返回值时当前类的引用。
  2. return?后面是*this

#include?<iostream>
#include?<string.h>
using namespace std;
class Test
{
private:
    int?val?= 0;
public:
????Test?&add(int?i)
    {
????????val?+=?i;   //?val?=?val?+?i;
        return *this;//返回类对象
    }
    int get_val()
    {
        return?val;
    }
};
int main()
{
    Test?t1;
????t1.add(1);
????t1.add(2);
????t1.add(100);
????cout?<<?t1.get_val() <<?endl;
    //?链式调用
    Test?t2;
????cout?<<?t2.add(2).add(21).add(300).add(221).get_val() <<?endl;
    return 0;
}

static?关键字

1?静态局部变量

使用static修饰局部变量,这样的变量就是静态局部变量。

静态局部变量在第一次调用的时候创建,指导程序结束后销毁,同一个类的所有对象共用这一份静态局部变量。

#include?<iostream>
using namespace?std;
class Test
{
public:
    void func()
    {
        int?a?= 1;
        static int?b?= 1;
????????cout?<< "a=" << ++a?<< "?" << &a?<<?endl;
????????cout?<< "b=" << ++b?<< "?" << &b?<<?endl;
    }

};
int main()
{
????Test?t1;
????t1.func(); //?2,2
????t1.func();

????Test?t2;
????t2.func();

????Test?t3;
????t3.func();

    return 0;
}

注意:a可能会在同一个内存地址,反复销毁创建。

2?静态成员变量

使用static修饰成员变量,这样的变量就是静态成员变量。

静态成员变量需要在类内声明,类外初始化。

一个类的所有对象共用一份静态成员变量,虽然静态成员变量可以使用对象调用,但是更建议直接使用类名调用。所以静态成员变量可以脱离对象使用(非静态成员无法直接通过类名调用),在程序开始运行时就开辟内存空间,直到程序运行结束销毁。

更推荐使用类名直接进行调用。代码的可读性更好

#include?<iostream>
using namespace?std;
class Test
{
public:
    int?a?= 1;
//????static?int?b?=?2;?//?错误,静态成员变量需要类内声明,类外初始化
    static int?b;
};
int?Test::b?= 2;
int main()
{
????cout?<<?Test::b?<< "?" << &Test::b?<<?endl;//静态成员变量可以通过类名直接调用,脱离对象使用。
????Test?t1;
????cout?<<?t1.a++ << "?" << &t1.a?<<?endl;
????cout?<<?t1.b++ << "?" << &t1.b?<<?endl;
????cout?<<?t1.a++ << "?" << &t1.a?<<?endl;
????cout?<<?t1.b++ << "?" << &t1.b?<<?endl;

????cout?<< "----------------" <<?endl;

????Test?t2;
????cout?<<?t2.a++ << "?" << &t2.a?<<?endl;
????cout?<<?t2.b++ << "?" << &t2.b?<<?endl;
????cout?<<?Test::b?<< "?" << &Test::b?<<?endl;
    return 0;
}

3?静态成员函数

使用static修饰成员函数,这样的函数就是静态成员函数。

与静态成员变量相似的有:

  • 都可以通过类名直接使用,也可以通过对象调用(建议使用类名直接调用)。
  • 可以脱离对象使用

静态成员函数没有this指针,不能在静态成员函数中调用同类中的其他非静态成员函数,但是静态成员函数,可以调用静态成员函数。

#include?<iostream>
using namespace?std;
class Test
{
public:
    void func0()
    {
        func1();
????????cout?<<"非静态成员函数0"<<endl;
    }
    static void func1()
    {
????????cout?<<"静态成员函数1"<<endl;
    }
    static void func2()
    {
//????????func0();//静态成员函数没有this指针,不能在静态成员函数中调用同类中的其他非静态成员函数,
        func1();//但是静态成员函数,可以调用静态成员函数。
????????cout?<<"静态成员函数2"<<endl;
    }
};
int main()
{
    Test::func1();
????Test?t1;
????t1.func0();
????t1.func1();
????t1.func2();
    return 0;
}

【思考】我如果想在静态成员函数里,调用非静态成员函数,应该怎么做?

  • 可以通过参数将对象传进来,因为静态成员函数没有this指针,例如:

#include?<iostream>
using?namespace?std;
class?Test
{
public:
????void?func0()
????{
????????func1();
????????cout?<<"非静态成员函数0"<<endl;
????}
????static?void?func1()
????{
????????cout?<<"静态成员函数1"<<endl;
????}
????static?void?func2(Test?&t)
????{
????????t.func0();
//静态成员函数没有this指针,不能在静态成员函数中调用同类中的其他非静态成员函数,
????????func1();//但是静态成员函数,可以调用静态成员函数。
????????cout?<<"静态成员函数2"<<endl;
????}
};
int?main()
{
????Test::func1();
????Test?t1;
????t1.func0();
????t1.func1();
????t1.func2(t1);
????return?0;
}

const关键字

1?const修饰成员函数

const修饰的成员函数,表示常成员函数,特性如下:

  • 可以调用成员变量,但是不能修改成员变量的值。
  • 不能调用非const修饰的成员函数,哪怕这个函数并没有修改成员变量。(const修饰的成员函数,不能调用非const?修饰的成员函数,只能调用const修饰的成员函数

建议只要成员函数不修改变量,就使用const修饰,例如:get、show等函数。

#include?<iostream>
using?namespace?std;
class?Demo
{
private:
????int?a;
public:
????Demo(int?a)
????{
????????this->a?=?a;
????}
????void?func()
????{
????????cout?<<?"哈哈哈哈"?<<?endl;
????}
????int?get_demo()?const
????{
????????return?a;
????}
????void?test()?const
????{
//????????a++;?//?错误?const修饰的成员函数,不能修改成员变量
????????cout?<<?a?<<?endl;
//????????func();?错误?const修饰的成员函数,不能调用非const?修饰的成员函数,只能调用const修饰的成员函数
????????cout?<<?get_demo()?<<?endl;

????????int?i?=?1;
????????i++;
????????cout?<<?i?<<?endl;
????}
};
int?main()
{
????Demo?demo(1);
????cout?<<?demo.get_demo()?<<?endl;
????demo.func();
????demo.test();
????return?0;
}

2?const修饰对象

const修饰的对象被称为常量对象,这种对象的成员变量值无法被修改,也无法调用非const的成员函数。

#include?<iostream>
using?namespace?std;
class?Demo
{
private:
????int?a;
public:
????int?b?=?20;
????Demo(int?a)
????{
????????this->a?=?a;
????}

????void?func()
????{
????????cout?<<?"哈哈哈哈"?<<?endl;
????}

????int?get_demo()?const
????{
????????return?a;
????}

????void?test()?const
????{
//????????a++;?//?错误?const修饰的成员函数,不能修改成员变量
????????cout?<<?a?<<?endl;
//????????func();?错误?const修饰的成员函数,不能调用非const?修饰的成员函数
????????cout?<<?get_demo()?<<?endl;

????????int?i?=?1;
????????i++;
????????cout?<<?i?<<?endl;
????}
};
int?main()
{
//????const?Demo?demo(1);
????Demo?const?demo(1);?//?两种初始化方式,等效于上一行
????cout?<<demo.get_demo()?<<?endl;

//????demo.func();?//?错误?const修饰的对象,无法调用非const的成员函数
????demo.test();
//????demo.b++;?//?错误const修饰的对象,无法修改成员变量
????cout?<<?demo.b?<<?endl;?//?可以调用,但是不能修改
????return?0;
}

3?const修饰成员变量

cosnt修饰的成员变量称为常成员变量,表示该成员变量的值无法被改变。

常成员变量有两种初始化的方式:

  • 直接赋值
  • 声明后赋值、使用构造初始化列表

两种方式一块使用时,前者失效,后者为准。

#include?<iostream>
using?namespace?std;
class?Demo
{
private:
????const?int?a?=?1;
????const?int?b?=?2;
????const?int?c?=?3;//初始化赋值
public:
????Demo(int?a,int?b,int?c):a(a),b(b),c(c){}//构造初始化列表赋值
????void?show()
????{
????????cout?<<?a?<<?"?"?<<?b?<<?"?"?<<?c?<<?endl;
????}
????void?test()
????{
????????//????????a++;?//?错误,const修饰的成员变量,无法被改变
????????//????????b++;
????????//????????c++;
????????cout<<"const修饰的成员变量,无法被改变"<<endl;
????}
};
int?main()
{
????Demo?demo(10,20,30);
????demo.test();
????demo.show();
????return?0;
}

4?const修饰局部变量

const修饰局部变量,表示该局部变量不可被修改。

这种方式常用于引用参数

#include?<iostream>
#include?<string.h>
using namespace?std;

class Demo
{
private:
    const int?a?= 1;
    const int?b?= 2;
    const int?c?= 3;

public:
    //?构造初始化列表
    Demo(int?a,int?b,int?c):a(a),b(b),c(c){}

    void show()
    {
????????cout?<<?a?<< "?" <<?b?<<"?"<<?c?<<?endl;
    }
    void test()
    {
        const int?d?= 10;
//????????d?=?20;???//?错误,const修饰的局部变量,无法被修改。
????????cout?<<?d?<<?endl;
    }

};

int main()
{
????Demo?d(10,20,30);
????d.show();   //?以列表为准
????d.test();
    return 0;
}

文章来源:https://blog.csdn.net/m0_74937538/article/details/135332445
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。