C++学习——初始化表,this指针和常函数,析构函数

5.初始化表

1)语法

class 类名{
    类名(形参表):成员变量1(初值),成员变量2(初值),...{}
};

2)多数情况下,使用初始化表和在构造函数中对成员变量进行初始化操作,并没有太大的区分,两种形式可以任选,但是有些特殊的场景需要使用初始化列表:

3)必须显示使用初始化列表的场景

①如果有类类型的成员变量(成员子对象),而该类又没有无参构造(必须有参构造),则必须使用初始化表来完成该成员子对象的初始化操作

#include <iostream>
using namespace std;
class A{
public:
    A(int i){
        cout << "A(int)" << endl;
        m_i = i;
    }
    int m_i;
};
class B{
public:
    B(void):m_a(123){
        cout << "B(void)" << endl;
    }
    A m_a;//成员子对象
};
int main(void)
{
    B b;
    cout << b.m_a.m_i << endl;//123
    return 0;
}

②如果类中有const或者引用型的成员变量,必须在初始化表显示的初始化,因为const和引用必须在定义时赋初值

#include <iostream>
using namespace std;
int num=20;
class A{
public:
    A(void){
        m_c = 10;
        m_r = num;
    }
    const int m_c;
    int& m_r;
};

int main()
{
    A a;
    cout << a.m_c << "," << a.m_r << endl;
}


//运行结果:
/*
initlist3.cpp: In constructor ‘A::A()’:
initlist3.cpp:6:9: error: uninitialized const member in ‘const int’ [-fpermissive]
         A(void){
         ^
initlist3.cpp:11:19: note: ‘const int A::m_c’ should be initialized
         const int m_c;
                   ^
initlist3.cpp:6:9: error: uninitialized reference member in ‘int&’ [-fpermissive]
         A(void){
         ^
initlist3.cpp:12:14: note: ‘int& A::m_r’ should be initialized
         int& m_r;
              ^
initlist3.cpp:7:16: error: assignment of read-only member ‘A::m_c’
             m_c=10;
                ^
*/

4)成员变量的初始化顺序和初始化表的顺序无关,而是由成员变量的声明顺序决定,不要使用一个成员变量去初始化另一个成员变量

注:以无参的方式创建对象是,不要加(),因为编译器会认为是函数的创建,不是对象的创建

A a();//a会被认为是一个A类型返回值的函数的声明
A a;   //以无参的方式创建对象

十五、this指针和常成员函数

1.this指针

1)类中的构造函数和成员函数(包括析构函数)都有一个隐藏的当前类类型的指针参数,名为this,在成员函数中,访问类中的其他成员,其本质都是通过this指针来实现的

①对于普通的成员函数,this指针指向的就是调用该函数的对象

②对于构造函数,this指针指向的是正在创建的对象

#include <iostream>
using namespace std;
class User{
public:
    /*User(const string& name,int age)
        :m_name(name),m_age(age){
        cout << "构造函数:" << this << endl;
    }*/
    //通过this指针区分成员变量和形参变量
    User(const string& m_name,int m_age){
        this->m_name = m_name;
        this->m_age = m_age;
    }
    void print(void){
        cout << m_name << ',' << m_age << 
            endl;
        cout << this->m_name << ',' << 
            this->m_age << endl;
    }/*编译以后
    void print(User* this){
        cout << this->m_name << ',' << 
            this->m_age << endl;
    }*/
private:
    string m_name;
    int m_age;
};
int main(void)
{
    User u1("马超",30);
    cout << "&u1:" << &u1 << endl;
    User u2("黄忠",50);
    cout << "&u2:" << &u2 << endl;
    u1.print();//User::print(&u1);
    u2.print();
}

2)需要使用this指针的场景

①区分作用域

②从成员函数中返回调用的自身

③从类的内部销毁对象

参考代码:

#include <iostream>
using namespace std;
class Counter{
public:
    Counter(int count=0):m_count(count){}
    //Counter& add(Counter* this)
    Counter& add(void){
        ++m_count;
        //this指向调用对象
        //*this就是调用对象自身
        return *this;//返回自引用
    }
    void destroy(void){
        //...
        cout << "this=" << this << endl;
        delete this;//对象自销毁
    }
    int m_count;
};
int main(void)
{
    Counter c;
    c.add().add().add();
    cout << c.m_count << endl;//3
        
    Counter* pc = new Counter(10);
    pc->add();
    cout << pc->m_count << endl;//11
    //delete pc;
    cout << "pc=" << pc << endl;
    pc->destroy();//(*pc).destroy()
    return 0;
}

2.常成员函数

1)在一个普通的成员函数后面加上const修饰,这个成员函数就是常函数

返回类型 函数名(形参表) const {//函数体}

2)常成员函数中的this指针是常指针,不能在常成员函数中修改其他成员变量的值

#include <iostream>
using namespace std;
class A{
public:
    A(int data = 0):m_data(data){} 
    void print(void) const {//常函数
        cout << m_data++ << endl;
        //cout << const_cast<A*>(this)
        //    ->m_data++ << endl;
    }
    /*void print(const A* this){
        cout << this->m_data++ << endl;
    }*/
private:
    mutable int m_data;
};
int main(void)
{
    A a(100);
    a.print();//100
    a.print();//101
}

注:被mutable关键字修饰的成员变量,可以再常函数中被修改

3)非const对象既可以调用常函数也可以调用非常函数,但是常对象只能调用常函数,不能调用非常函数

#include <iostream>
using namespace std;

class A{
public:
    //void func1(const A* this){
    void func1(void) const {
        cout << "常函数" << endl;
        //func2();//error
    }
    //void func2(A* this)
    void func2(void) {
        cout << "非常函数" << endl;
        //func1();//ok
    }
};
int main(void)
{
    A a1;
    a1.func1();//A::func1(&a1),A*
    a1.func2();//A::func2(&a1),A*
    const A a2 = a1;
    a2.func1();//A::func1(&a2),const A*
    //a2.func2();//A::func2(&a2),const A*
    
    const A* pa = &a1;//pa:常指针
    pa->func1();//A::func1(pa)
    //pa->func2();

    const A& ra = a1;//ra:常引用
    ra.func1();
    //ra.func2();

}

注:常对象包括常引用和常指针

4)函数名和形参表相同的成员函数,其长版本和非常版本也可以构成重载关系,常对象调用常版本,非常对象调用非常版本

#include <iostream>
using namespace std;
class A{
public:
    void func(void) const {
        cout << "func常版本" << endl;
    }
    void func(void) {
        cout << "func非常版本" << endl;
    }
};
int main(void)
{
    A a1;
    a1.func();
    const A a2 = a1;
    a2.func();

}

十六、析构函数

1)语法

class 类名{
    ~类名(void){
        //主要负责清理对象声明周期中的动态资源    
    }
};

1)函数名一定是“~类名”

2)没有返回值,没有参数

3)析构函数不能被重载,一个类里面只能有一个析构函数

#include <iostream>
using namespace std;
class A{
public:
    A(void){
        cout << "A(void)" << endl;
    }
    ~A(void){
        cout << "~A(void)" << endl;
    }
};
class B{
public:
    B(void){
        cout << "B(void)" << endl;
    }
    ~B(void){
        cout << "~B(void)" << endl;
    }
    A m_a;
};
int main(void)
{
    B b;
    return 0;
}

2.当对象被销毁时,该对象的析构函数自动被执行

1)栈对象当其离开作用域时,析构函数被右花括号“}”调用

2)堆对象,在delete时调用析构函数

3.如果类自己没有定义析构函数,那么编译器会为该类提供一个缺省的析构函数

1)对基本类型的成员变量,什么也不做

2)对类类型的成员变量(成员子对象),自动调用相应类的析构函数

4.对象的创建和销毁过程

1)创建

①分配内存

②构造成员子对象(按声明顺序)

③执行构造函数的代码

2)销毁

①执行析构函数代码

②析构成员子对象(按声明逆序)

③释放内存

猜你喜欢

转载自blog.csdn.net/isco22/article/details/88169347
今日推荐