命名空间
- 命名空间主要是用来解决命名冲突的;
// 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 XY
与using 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
是父类,Student
与Worker
是子类;
对象的内存布局
- 父类的成员分布在前面,然后再分布自己的成员;
#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;
}
- 控制台调试结果为:
成员的访问权限
- 成员的访问权限,继承有三种方式:
-
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 = age
,m_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;
}
- 首先我们必须知道构造函数在调用时,就已经创建了一个对象,所以直接在构造函数内部再调用其他的构造函数,又会创建一个新的对象,如上所示,两个对象,两块不同的内存地址空间;
- 为了实现构造函数的相互调用,必须在
初始化列表中
调用其他构造函数,如下所示:
#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;
}
- 调试结果如下:
初始化列表与默认参数
#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;
}
- 控制台打印结果:
- 如果子类的构造函数,显示的调用了父类的有参构造函数,那么就不会再去默认的调用父类的无参构造函数;
#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,若访问下一个成员的内存,可能是别的内存,不安全;
网友评论