命名空间、构造函数、析构函数、继承、初始化列表

2019-10-11  本文已影响0人  叶子扬
C++.png

构造函数(Constructor)

构造函数的调用
struct Person{
    int m_age;
    
    Person(){
        cout << "Person()" << endl;
    }
    Person(int age){
        cout << "Person(int age)" << endl;
    }
};

// 全局区
Person g_p1;    // 调用Person()
Person g_p2();  // 函数声明,函数名字是g_p2
Person g_p3(20);// 调用Person(int)

int main() {

    // 栈空间
    Person p1;      // 调用Person()
    Person p2();    // 函数声明,函数名字是p2
    Person p3(20);  // 调用Person(int)

    // 堆空间
    Person *p4 = new Person;    // 调用Person()
    Person *p5 = new Person();  // 调用Person()
    Person *p6 = new Person(20);// 调用Person(int)
    return 0;
}

默认情况下,成员变量的初始化

如果自定义了构造函数,除了全局区,其他内存空间的成员变量默认都不会被初始化,需要开发人员手动初始化

struct Person{
    int m_age;
};

// 全局区
Person g_p1;    // 成员标变量初始化为0

int main() {

    // 栈空间
    Person p1; // 成员标变量不初始化
    
    // 堆空间
    Person *p2 = new Person;        // 成员标变量不初始化
    Person *p3 = new Person();      // 成员标变量初始化为0
    Person *p4 = new Person[3];     // 成员标变量不初始化
    Person *p5 = new Person[3]();   // 3个对象的成员标变量初始化为0
    Person *p6 = new Person[3]{};   // 3个对象的成员标变量初始化为0
    return 0;
}

成员变量的初始化

对象初始化

Person(){
        memset(this, 0, sizeof(Person));
    }

析构函数(Destructor)

对象的内存管理

声明和实现分离

就是类的域不同::

命名空间

namespace YY {
    int g_age;
    class Person{
    public:
        
        Person(){
            cout << "Person()" << endl;
        }
        ~Person(){
            cout << "~Person()" << endl;
        }
        void run(){
            cout << "run()" << endl;
        }
    };
};
int main() {

    YY::g_age = 20;
    cout << "YY::g_age = " << YY::g_age << endl;
    
    YY::Person person = YY::Person();
    person.run();
    return 0;
}
// log:
YY::g_age = 20
Person()
run()
~Person()

思考:下边的代码能通过编译吗

namespace FX {
    int g_age;
}
namespace YY {
    int g_age;
}
int main() {
    using namespace YY;
    using namespace FX;
    g_age = 20; // 报错:Reference to 'g_age' is ambiguous
    return 0;
}

命名空间的嵌套

有个默认的全局命名空间,我们创建的命名空间默认都嵌套在它里面

namespace YY {
    namespace XX {
        int g_age;
    }
};

int g_age;

int main() {
    ::g_age = 20;
    ::YY::XX::g_age = 30;
    
    return 0;
}
namespace YY {
    namespace XX {
        int g_age;
    }
};

// 以下的用法都是合法的
int main() {
    {
        using namespace YY::XX;
        g_age = 20;
    }
    
    {
        using  YY::XX::g_age;
        g_age = 20;
    }
    
    {
        YY::XX::g_age = 20;
    }
    
    return 0;
}

命名空间的合并

以下2种写法是等价的

namespace YY {
    int g_age1;
};
namespace YY {
    int g_age2;
}
namespace YY {
    int g_age1;
    int g_age2;
}

其他编程语言的命名空间

继承

对象的内存布局

成员访问权限

初始化列表

struct Student {
    int m_age;
    int m_height;
    Student(int age, int height){
        this->m_age = age;
        this->m_height = height;
    }
};

struct Student {
    int m_age;
    int m_height;
    Student(int age, int height): m_age(age), m_height(height){}
};

思考:
m_age、m_height的值是多少

int myAge(){return 20;};
int myHeight(){return 170;};

struct Student {
    int m_age;
    int m_height;
    Student(int age, int height): m_age(myAge()), m_height(myHeight()){}
};

int main() {
    Student s(10,140);
    return 0;
}
// 20, 170
struct Student {
    int m_age;
    int m_height;
    // 警告:Field 'm_height' is uninitialized when used here
    Student(int age, int height): m_age(m_height), m_height(height){}
};

int main() {
    Student s(10,140);
    return 0;
}
// 未知、140

构造函数的互相调用

struct Student {
    int m_age;
    int m_height;
    Student():Student(0, 0){};
    Student(int age, int height): m_age(age), m_height(height){}
    
    void display(){
        cout << m_age << ", "<< m_height << endl;
    }
};

int main() {
    Student s0;
    s0.display();
    
    Student s(10,140);
    s.display();
    return 0;
}
// log:
0, 0
10, 140

注意:下面的写法是错误的,初始化的是一个临时对象

struct Student {
    int m_age;
    int m_height;
    Student(){
        Student(0, 0);
    };
    Student(int age, int height): m_age(age), m_height(height){}
    
    void display(){
        cout << m_age << ", "<< m_height << endl;
    }
};

int main() {
    Student s0;
    s0.display();
    
    Student s(10,140);
    s.display();
    return 0;
}
// log:
-272632680, 32766
10, 140

初始化列表与默认参数配合使用

struct Student {
    int m_age;
    int m_height;
    Student(int age = 0, int height = 0): m_age(age), m_height(height){}
    
    void display(){
        cout << m_age << ", "<< m_height << endl;
    }
};

int main() {
    Student s1;
    Student s2(20);
    Student s3(20, 170);
    
    s1.display();
    s2.display();
    s3.display();
    return 0;
}
// log:
0, 0
20, 0
20, 170

父类的构造函数

继承体系下的构造函数示例

struct Person {
    int m_age;
    Person(): Person(0){};
    Person(int age = 0): m_age(age) {}
};

struct Student: public Person {
    int m_no;
    Student(): Student(0, 0){};
    Student(int age, int no): Person(age), m_no(no) {}
    
    void display(){
        cout << m_age << ", "<< m_no << endl;
    }
};

int main() {
    Student s1;
    s1.display();
    
    Student s3(2,40);
    s3.display();
    
    return 0;
}
// log:
0, 0
2, 40

构造、析构顺序

构造和析构顺序相反

struct Person {
    Person(){
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};

struct Student: public Person {
    Student(){
        cout << "Student()" << endl;
    }
    ~Student(){
        cout << "~Student()" << endl;
    }
};

int main() {
    Student s1;
    
    return 0;
}
// log:
Person()
Student()
~Student()
~Person()

父类指针、子类指针

上一篇 下一篇

猜你喜欢

热点阅读