美文网首页
C++入门05 --命名空间,继承,访问权限,初始化列表

C++入门05 --命名空间,继承,访问权限,初始化列表

作者: YanZi_33 | 来源:发表于2021-08-12 12:26 被阅读0次

命名空间

  • 命名空间主要是用来解决命名冲突的;
//  main.cpp
//  C++12_命名空间
//
//  Created by ljj on 8/12/21.
//

#include <iostream>

using namespace::std;

void test(){
    cout << "test()" << endl;
}

namespace XY {
    //全局变量
    int g_no;
 
    class Person {
    public:
        int m_age;
    };
    
    void test(){
        cout << "XY test()" << endl;
    }
}

namespace YY {
    int g_no;

    class Person{
    public:
        int m_age;
    };

    void test(){
        cout << "XY test()" << endl;
    }
}

int main(int argc, const char * argv[]) {
    //使用XY命名空间中的定义
    XY::Person person1;
    person1.m_age = 10;
    
    //使用YY命名空间中的定义
    YY::Person person2;
    person2.m_age = 20;
    
    //注意是全局变量
    XY::g_no = 100;
    YY::g_no = 200;
    
    //函数调用
    test();
    XY::test();
    YY::test();
        
    return 0;
}
  • namespace xxxx { }:命名空间的定义;
  • 利用::域运算符,使用命名空间中的定义;
#include <iostream>

using namespace::std;

namespace XY {
    //全局变量
    int g_no;
 
    class Person {
    public:
        int m_age;
    };
    
    void test(){
        cout << "XY test()" << endl;
    }
}

int main(int argc, const char * argv[]) {
    
    //表明下面用到的特定元素 是来自XY的命名空间
    using namespace XY;
    Person person;
    person.m_age = 33;
    test();
    
    return 0;
}
  • 在调用的地方,声明命名空间using namespace XY,表明下面用到的特定元素 都是来自XY的命名空间;
#include <iostream>

using namespace::std;

namespace XY {
    //全局变量
    int g_no;
 
    class Person {
    public:
        int m_age;
    };
    
    void test(){
        cout << "XY test()" << endl;
    }
}

int main(int argc, const char * argv[]) {
    
    //表明下面用到的特定元素 是来自XY的命名空间
    using namespace XY;
    Person person;
    person.m_age = 33;
    test();
    g_no = 300;
    
    return 0;
}
  • 先声明某个元素属于命名空间,using XY::Person,然后再使用;
#include <iostream>

using namespace::std;

namespace XY {
    //全局变量
    int g_no;
 
    class Person {
    public:
        int m_age;
    };
    
    void test(){
        cout << "XY test()" << endl;
    }
}

int main(int argc, const char * argv[]) {
    
    //Person与g_no是来自于命名空间XY
    using XY::Person;
    using XY::g_no;
    Person person;
    g_no = 30;
    
    return 0;
}
  • 先声明Person与g_no是来自于命名空间XY;
#include <iostream>

using namespace::std;

namespace XY {
    //全局变量
    int g_no;
 
    class Person {
    public:
        int m_age;
    };
    
    void test(){
        cout << "XY test()" << endl;
    }
}

namespace YY {
    int g_no;

    class Person{
    public:
        int m_age;
    };

    void test(){
        cout << "XY test()" << endl;
    }
}

int main(int argc, const char * argv[]) {
    
    using namespace XY;
    test();
    
    using namespace YY;
    test(); //报错
    
    return 0;
}
  • 同时使用using namespace XYusing namespace YY会出现报错的;
命名空间的嵌套
#include <iostream>

using namespace::std;

namespace AA {
    namespace BB {
        int g_num;
        class Cat {
        public:
            int m_age;
        };
    }
}

int main(int argc, const char * argv[]) {
    
    AA::BB::g_num = 300;
    
    AA::BB::Cat *c = new AA::BB::Cat();
    c->m_age = 20;

    using namespace AA::BB;
    g_num = 400;

    return 0;
}
命名空间的合并
namespace MM {
    int m_age;
}

namespace MM {
    int m_weight;
}

namespace MM {
    int m_age;
    int m_weight;
}
  • 上下两种写法是等价的,即命名空间是可以合并的;

继承

  • 继承,可以让子类拥有父类的所有成员(变量和函数);
#include <iostream>

using namespace::std;

struct Person {
    int m_age;
    
    void run(){
        cout << "run()" << endl;
    }
};

struct Student : Person{
    int m_score;
    
    void study(){
        cout << "study()" << endl;
    }
};

struct Worker : Person{
    int m_salary;
    
    void work(){
        cout << "work()" << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Student student;
    student.m_age = 10;
    student.run();
    student.study();
    
    Worker work;
    work.m_age = 33;
    work.run();
    work.work();
    
    return 0;
}
  • Person是父类,StudentWorker是子类;
对象的内存布局
  • 父类的成员分布在前面,然后再分布自己的成员;
#include <iostream>

using namespace::std;

struct Person {
    int m_age;
};

struct Student : Person {
    int m_no;
};

struct GoodStudent : Student{
    int m_money;
};


int main(int argc, const char * argv[]) {
    
    GoodStudent gs;
    gs.m_age = 20;
    gs.m_no = 1;
    gs.m_money = 2000;
    
    cout << "gs size = " << sizeof(gs) << endl;
    cout << &gs << endl;
    cout << &gs.m_age << endl;
    cout << &gs.m_no << endl;
    cout << &gs.m_money << endl;

    return 0;
}
  • 控制台调试结果为:
Snip20210812_141.png

成员的访问权限

  • 成员的访问权限,继承有三种方式:
  • public:公共的么,任何地方都可以访问;(struct默认)
  • protected:子类内部,当前类内部可以访问;
  • private:私有的,只有当前类内部可以访问;(class默认)
#include <iostream>

using namespace::std;

struct Person {
protected:
    int m_age;
    
    void run(){
        
    }
};

struct Student : Person {
    int m_no;
    
    void study(){
        this->m_age = 30;
    }
};

int main(int argc, const char * argv[]) {
    
    Person person;
    person.m_age = 30; //报错
    
    return 0;
}
  • 子类内部访问父类成员的权限,是以下权限中权限最小的那个:
    • 成员本身的权限;
    • 上一级父类的继承权限;
  • 访问权限不影响对象的内存布局;

初始化列表

  • 初始化列表是一种便捷的初始化成员变量的方式;
  • 初始化列表的使用只能在构造函数中;
  • 初始化列表的初始化顺序只跟成员变量的声明顺序有关;
#include <iostream>

using namespace::std;

struct Person {
    int m_age;
    int m_height;
    
    Person(){
        this->m_age = 0;
        this->m_height = 0;
    }
    
//    Person(int age,int height){
//        this->m_age = age;
//        this->m_height = height;
//    }
    
    Person(int age,int height) :m_age(age),m_height(height){
        
    }    
    
    void display(){
        cout << "m_age = " << this->m_age << endl;
        cout << "m_height = " << this->m_height << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Person person1;
    person1.display();

    cout << "-----------" << endl;
    
    Person person2(10,20);
    person2.display();
    
    
    return 0;
}
  • Person(int age,int height) :m_age(age),m_height(height) { },这是初始化列表,与上面的注释的构造函数是等价的;
  • m_age = agem_height = height
  • Person(int age,int height) :m_age(11),m_height(12) { },无论外界传参多少,m_age = 11,m_height = 12;
  • Person(int age,int height) :m_height(height),m_age(age):将m_height放在前面,但是赋值依然是先赋值m_age,因为初始化列表的初始化顺序只跟成员变量的声明顺序有关;

构造函数的相互调用

#include <iostream>

using namespace::std;

struct Person {
    int m_age;
    int m_height;
    
    Person(){
        //0x7ffeefbff3a8
        cout << "Person()" << this << endl;
        //直接调用构造函数,又会创建一个对象
        Person(1,2);
    }
    
    Person(int age,int height){
        //0x7ffeefbff360
        cout << "Person(int age,int height)" << this << endl;
        this->m_age = age;
        this->m_height = height;
    }
    
    void display(){
        cout << "m_age = " << this->m_age << endl;
        cout << "m_height = " << this->m_height << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Person person1;
    person1.display();
    
    return 0;
}
  • 首先我们必须知道构造函数在调用时,就已经创建了一个对象,所以直接在构造函数内部再调用其他的构造函数,又会创建一个新的对象,如上所示,两个对象,两块不同的内存地址空间;
Snip20210812_142.png
  • 为了实现构造函数的相互调用,必须在初始化列表中调用其他构造函数,如下所示:
#include <iostream>

using namespace::std;

struct Person {
    int m_age;
    int m_height;
    
    //在初始化列表中 调用其他构造函数
    Person() :Person(1,2){
        cout << "Person()" << this << endl;
        //直接调用构造函数,又会创建一个对象
    }
    
    Person(int age,int height){
        cout << "Person(int age,int height)" << this << endl;
        this->m_age = age;
        this->m_height = height;
    }
   
    void display(){
        cout << "m_age = " << this->m_age << endl;
        cout << "m_height = " << this->m_height << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Person person1;
    person1.display();
    
    return 0;
}
  • 调试结果如下:
Snip20210812_143.png
初始化列表与默认参数
#include <iostream>

using namespace::std;

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

int main(int argc, const char * argv[]) {
    
    Person person1;
    Person person2(100);
    Person person3(10,20);
    person1.display();
    person2.display();
    person3.display();
    
    return 0;
}
  • Person(int age = 0,int height = 0) : m_age(age),m_height(height)初始化列表,默认参数均为0;
#include <iostream>

using namespace::std;

struct Person {
    int m_age;
    int m_height;

    
    Person(int age = 0,int height = 0);
    
    void display(){
        cout << "m_age = " << this->m_age << endl;
        cout << "m_height = " << this->m_height << endl;
    }
};

//默认参数只能写在函数声明
//初始化列表只能写在函数实现
Person::Person(int age,int height) : m_age(age),m_height(height){
    cout << "Person(int age,int height)" << this << endl;
}

int main(int argc, const char * argv[]) {
    
    Person person1;
    Person person2(100);
    Person person3(10,20);
    person1.display();
    person2.display();
    person3.display();

    return 0;
}
  • 如果函数的声明与实现是分离的,那么:
  • 默认参数只能写在函数声明;
  • 初始化列表只能写在函数实现;

父类的构造函数

  • 子类的构造函数默认会调用父类的无参的构造函数,目的在于初始化父类中的成员变量;
#include <iostream>

using namespace::std;

class Person {
    
public:
    Person(){
        cout << "Person()" << endl;
    }

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

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

    ~Student(){
        cout << "~Student()" << endl;
    }
};


class GoodStudent : Student {
    
public:
    GoodStudent(){
        cout << "GoodStudent()" << endl;
    }
};


int main(int argc, const char * argv[]) {
    
    GoodStudent gs;
    
    return 0;
}
  • 控制台打印结果:
Snip20210812_144.png
  • 如果子类的构造函数,显示的调用了父类的有参构造函数,那么就不会再去默认的调用父类的无参构造函数;
#include <iostream>

using namespace::std;

class Person {
    int m_age;
public:
    Person(){
        cout << "Person()" << endl;
    }
    
    Person(int age) : m_age(age){
        cout << "Person(int age)" << endl;
    }
    
};

class Student : Person {
    int m_score;
public:
    Student(){
        cout << "Student()" << endl;
    }
    //初始化列表 调用父类的构造函数(有参的)
    Student(int age,int score) : m_score(score),Person(age){
        cout << "Student(int score)" << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Student student(10,100);
    
    return 0;
}
  • Student(int age,int score) : m_score(score),Person(age):子类Student的初始化列表中,调用父类Person的有参构造函数,就不会再去调用Person的无参构造函数;

  • 如果父类缺少无参构造函数,子类的构造函数必须显示调用父类的有参构造函数;

#include <iostream>

using namespace::std;

class Person {
    int m_age;
public:
    Person(int age) : m_age(age){
        cout << "Person(int age)" << endl;
    }
    
};

class Student : Person {
    int m_score;
public:
    //父类没有无参的构造函数;
    //子类的构造函数,必须调用父类的有参构造函数,否则报错;
    Student() : Person(0){
        cout << "Student()" << endl;
    }
    //初始化列表 调用父类的构造函数(有参的)
    Student(int age,int score) : m_score(score),Person(age){
        cout << "Student(int score)" << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Student student();
    
    return 0;
}
  • 当堆对象销毁回收时,先调用自己的析构函数,再调用父类的析构函数;

父类指针,子类指针

  • 父类指针可以指向子类对象,是安全的;
  • 子类指针指向父类对象,是不安全的;
#include <iostream>

using namespace::std;

class Person {
public:
    int m_age;
    
};

class Student : public Person {
public:
    int m_score;
    
};

int main(int argc, const char * argv[]) {
    
    //父类指针 指向子类对象
    Person *s = new Student();
    s->m_age = 30;
    
    //子类指针 指向父类对象
    Student *p = (Student *)new Person();
    
    return 0;
}
Snip20210812_145.png
  • Person *s,只会访问到m_age成员,不会越界;
  • Student *p,可访问m_age与m_score,但person对象只有m_age,若访问下一个成员的内存,可能是别的内存,不安全;

相关文章

  • C++入门05 --命名空间,继承,访问权限,初始化列表

    命名空间 命名空间主要是用来解决命名冲突的; namespace xxxx { }:命名空间的定义; 利用::域运...

  • 2021-04-25周日

    RBAC基于角色的访问控制角色绑定角色:role :特定命名空间访问权限clusterrole:所有命名空间访问权...

  • C++继承和派生

    C++通过继承关系,实现了代码的可重用性。 public表示继承方式,也表示访问权限 一、继承方式和访问权限的影响...

  • 06.析构函数,命名空间,继承,成员访问权限、初始化列表

    一, 二. 三。 四, 五。 六, 七, 八. 九, 十: 十一. 十二。 十三。 十四. 十五. 十六。 十七。...

  • C++访问权限-继承-继承方式

    几年不碰C++,如今看来已路人。 C++是我的入门语言,编程处女地就是给了她,但我明显没有耕耘好,那个时候不知道是...

  • C++ 基础知识点大纲

    C++ C++对C的加强 namespace命名空间 C++命名空间基本概念 C++命名空间定义,使用语法,意义 ...

  • C++ 的社会繁衍

    把 C++ 想象成人类社会。 访问权限、继承、友元将无比真实的反应人类社会中的种种关系。 一、类内部访问权限 +-...

  • C++继承权限和继承方式

    类成员的访问权限 继承方式 派生类的成员(及友元)对基类成员的访问权限只与基类中的访问说明符有关。派生列表中访问说...

  • c++语法2

    接上篇我们继续学习静态成员、友元函数、继承、多重继承,继承访问权限等 静态成员与友元函数:c++中静态成员与jav...

  • C++命名空间

    C++ 命名空间 C++为了区分多个xyz的函数的时候,需要使用命名空间进行区分。 定义命名空间 using 使用...

网友评论

      本文标题:C++入门05 --命名空间,继承,访问权限,初始化列表

      本文链接:https://www.haomeiwen.com/subject/hqklbltx.html