c++ 命名空间、三大特征以及封装性

名字空间

namespace 的基础与扩展

cpp 复制代码
#include <iostream>
using namespace std;

namespace ns
{
    int a = 3;
    
    float f(int x)
    {
        return x / 2;
    }
    
    namespace ns_ns	// 可以进行嵌套
	{
    	int a = 6;
    
    	float f(int x)
    	{
        	return x / 3;
    	}  
	}
}

namespace ns
{
    int b = 5;	// 直接扩充成员
}


int main()
{
    cout << ns::a << endl;	// 使用自创的名字空间,必须要告知来源
    cout << ns::f(6) << endl;
    
    cout << ns::ns_ns::a << endl;	// 同样的,嵌套使用必须说明来源
    cout << ns::ns_ns::f(6) << endl;
    
    cout << ns::b << endl;
    
    return 0;
}

若两个命名空间出现相同名字,则只需在调用时明确告知来源即可,
如:假设存已命名空间 name 内部包含 a,则

cout << ns::a << endl;
cout << name::a << endl;

面向对象三大特征

封装

把对象的属性和功能结合成一个独立的系统单位。(尽可能隐藏内部细节,对外形成屏障)

如:人使用电脑,只需要知道键位功能,不需要知道键位是如何绑定函数调用的。

继承

若类的对象A拥有另一个类B的全部属性与服务,称作类A对类B的继承。

如:机动车共有特性发动机,而小汽车、摩托车等都继承了该共有属性。

多态

指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在一般类及其各个 特殊类中具有不同的语义

类的封装

类与对象的定义

相似于 c 语言的结构体,但存在以下区别:

1、含有作用域限定符

2、含有函数,也就是类的自身行为(类方法)

cpp 复制代码
#include <iostream>

using namespace std;

class A
{
    public:	// 若不添加,默认是 private
    	int a;
    
    private:
    	// 类方法:类中的函数
    	void show()
        {
            cout << a << endl;
        }
};


int main()
{
    A a1;
    
    a1.a = 10;
    
    a1.show();	// 通过类产生的对象来调用方法
    
    return 0;
}

类成员权限限定符

公有成员(public):任何地方都可以访问

保护成员(protected);只能在本类或其他后代类中访问

私有成员(private);只能在本类中访问

cpp 复制代码
一般原则:
    1、类数据属性,设定为私有;
    2、类方法,设定为公有;

#include <iostream>
using namespace std;

class Kitty
{
    public:
    	void eat() { cout << "吃饭" << endl; }
    	void sleep() { cout << "睡觉" << endl; }
    	void actCute() { cout << "卖萌" << endl; }
    	void f() { cout << "父类 f" << endl; }
};

class A : public Kitty
{
    public:
    	void f() { cout << "子类 f" << endl; }
};


int main()
{
    Kitty myCat;
    
    myCat.eat();
    myCat.sleep();
    myCat.actCute();
    myCat.f();	// Kitty::f();
    
    A a;
    a. f	 	();	// A::f(); 在本来对象可以简写调用
    a. Kitty::f	();	// 此时在子类调用从父类继承下来的方法,只需要明确说明即可
    
    return 0;
}

注意:被 protected 和 private 修饰,不可以被类直接调用

类的构造函数

概念:类的特殊成员,专门用于初始化类的各项数据(分配内存、变量初始化)

特点:

1、任何类都必然有至少一个构造函数,可以重载

2、若类显式定义构造函数,则默认无参构造函数会被取消(调用系统默认构造函数,这样就无法得知构造函数干啥。所以不要使用系统的默认构造函数);若无显示定义构造函数,则系统会自动添加一个隐式构造函数

3、每当分配一个类对象时,构造函数会被自动调用

4、构造函数无返回值类型(不是void),且必须与类名相同

5、构造函数不被设置为静态成员函数,构造函数的函数首部之前或之后不能用const修饰

cpp 复制代码
#include <iostream>
using namespace std;

class Node
{
    public:
    	// 特别注意:下面这种情况,两种构造函数都写了,那么就看对象创建时是否带参数
    	// 若默认无参构造函数未显式写出,而类对象创建时不带参数,那么就会报错,因为没有匹配的构造函数
    	Node() { cout << "我是默认构造函数" << endl; }
    	Node(int a) { cout << "我是显式的构造函数,我的编号是:" << a << endl; }
    	Node(int a, float b);	// 函数重载
    
    private:
    	string name;	// 不可以直接赋值
    	int high;
};


int main()
{
    // 动态分配会在堆区,而不会出现在栈区,这就是需要动态分配的原因
    Node node;
    // Node *node = new Node;	//普遍应用的一种方式,通过 new 可以调用构造函数,这是 malloc 不具备的(本质就是 new 除了会分配内存,还会调用构造函数进行变量初始化,而 malloc 只能分配内存,不能初始化)
    
    return 0;
}




小小认知:( 变量 )
    初始化:本质是为变量申请开辟内存空间,并没有直观的体现
    赋值:将数值存储在已初始化变量上,就是存储在内存空间中
    
    所以,构造函数的变量初始化是为了更加细化的给变量分配内存空间

this 指针

cpp 复制代码
#include <iostream>
using namespace std;

class Node
{
    public:
    	Node(string name) { this->name = name }	// 用来区分哪个是传参,哪个是本身,当然可以不用相同的名字
    	// 若要返回本身
    	Node f() { return *this; }
    
    private:
    	string name;	// 不可以直接赋值
    	int high;
};


int main()
{
    Node node("老六");
    
    return 0;
}

类的析构函数

概念:类的特殊成员,专门用于处理类对象被释放时的收尾工作

特点:

1、任何类有且仅有一个析构函数,不可以重载

2、若类显式定义析构函数,则默认无参构造函数会被取消;若无显示定义析构函数,则系统会自动添加一个隐式析构函数

3、每当释放一个类对象时,析构函数会被自动调用

4、构造函数无返回值类型(不是void),也没有参数,且必须与类名相同,且在前面多一个波浪号

5、如果类对象的作用域相同,那么销毁时析构函数的执行顺序与构造函数相反

cpp 复制代码
#include <iostream>

using namespace std;

class Node
{
    public:
    	Node() { cout << "我是构造函数" << endl; }
    	~Node() { cout << "我是析构函数" << endl; }
};


int main()
{
    Node *node = new Node;
    
    delete node;
    
    return 0;
}

拷贝构造函数

一种特殊的构造函数,其作用是在构造对象时,复制其他对象的所有成员。

1、拷贝构造函数,要求形参中有一个当前类的类对象

2、若没有就使用默认,若存在则使用存在的,特别需要注意的是:显式的拷贝构造函数基本不会影响已存在的默认拷贝构造函数,除非提供了单参构造函数,且参数类型是类类型的引用

3、拷贝分为浅拷贝和深拷贝,浅拷贝只拷贝值,深拷贝还会拷贝内存(这样也就不会导致重复释放同一个空间)

4、若显示声明和定义拷贝构造函数后,类中的的所有成员变量需要手动拷贝

5、当使用一个老对象去构造一个新对象时会调用拷贝构造函数,如果没有显示声明和定义拷贝构造函数时,类中的非指针类成员的值可以拷贝。默认拷贝构造函数负责执行了值的拷贝

三种应用场景:

(1)用一个老对象构造一个新对象,或者新对象赋给老对象

(2)当函数的形参是一个非引用的类对象时,形参对实参的传递时

(3)函数返回一个非引用的类对象时

cpp 复制代码
#include <iostream>

using namespace std;

class Node
{
    public:
    	Node(int a) { cout << a << endl; }
    	Node(const Node &p) { cout << "调用拷贝构造" << endl; }
};


int main()
{
    Node *node = new Node(1);
    Node *node1 = node;	// 会自动调用拷贝构造函数
    
    delete node;
    delete node1;	// 这会导致 double free ,所以需要进行深拷贝(将内存空间也要拷贝一份)
    
    return 0;
}
-------------------------------------------------- 深拷贝与浅拷贝 --------------------------------------------------
系统默认拷贝构造是浅拷贝,也就是相当于取别名,复制多个指针,但还是指向同一块内存空间。这样就会造成一个结果:重复释放了某一块内存空间,所以一般需要深拷贝

以下重点讲解怎么进行深拷贝:

#include <iostream>
#include <string>
using namespace std;

class A
{
    public:
    	A() { p = new char[100]; }
    	~A() { delete p; }
    
    	// 将拷贝构造函数进行重写,另外需要开辟空间,改造成深拷贝
    	A(const A &r)
        {
            if(r.p != nullptr)
            {
                p = new char[100];
                memcpy(p, r.p, 100);
            }
            else
                p = nullptr;
        }
            
    private:
    	char *p;
    	int a;
}

空类中默认的类方法

无参构造函数 析构函数 拷贝构造函数 赋值运算符函数

const 成员

const基本语义就是将其修饰的符号作只读化处理(不可修改)。

cpp 复制代码
#include <iostream>
using namespace std;

class person
{
    public:
    	person();
    	~person();
    
    private:
    	const unsigned int ID;	// const 修饰类成员变量
    
    public:
    	void studentInfo() const;	// const 修饰类方法
};

// 方式一:类构造函数初始化列表中初始化
person::person(unsigned int id)
    : ID(id)
{
	        
}

// 方式二:类定义语句中初始化
class person
{
    private:
    	const unsigned int ID = 12345;
};

注意:
    1、方式一可以通过构造函数传递不同的参数来给 ID 不同初始值 ---- 适用场景:学生的学号
    2、方式二则是所有对象被构造出来的 ID 都是一样的且不可修改 ---- 适用场景:学生的学校
-------------------------------------------------- 实际代码展示 ---------------------------------------------------
#include <iostream>
using namespace std;

class Student
{
    private:
    	const string schoolName = "粤嵌";	// 所有成员都在这个学校
    	const int ID;
    
    public:
    	Student(int id)
            : ID(id)	// 所有类对象都会有不同的 ID
        {
        }
    
    	// 打印学生信息
    	void showInfo() const	// 提高程序运行效率,只要确保该函数不会修改数据,就可以使用 const
        {
            cout << "我的学校" << schoolName << endl;
            cout << "我的ID" << ID << endl;
        }
};


int main()
{
    Student *luo = new Student(1);
    
    luo->showInfo();	// 重要认知:类成员方法是可以直接使用类成员属性的,并不需要传参。
    
    return 0;
}




注意:
    1、类方法的 const 关键字,要放在函数参数列表之后
    2、在类方法 声明 和 定义 中都需要加上 const ,因为这是重载的依据之一
    3、被 const 修饰的类方法不能访问类的非 const 方法,也不能对该类的其他数据成员赋值

类静态成员的设计和语法

当类成员被static修饰时,被称为静态成员。(本质:限制其作用域范围)

类成员数据:表达类的属性,而不是具体对象的属性

类成员方法:表达类的行为,而不是具体对象的行为

cpp 复制代码
#include <iostream>
using namespace std;

class Student
{
    private:
    	// 个人信息(单个对象属性)
    	unsigned int ID;
    	string name;
    
    	// 群体信息(类类型本身的属性)
    	static int total;	// 总人数
    
    public:
    	Student() { total++; }
    	~Student() { total--; }
    	
    	// 获取学生总人数
    	static void totalStudentNumber();	// 不依赖于类而存在
        {
            cout << "总人数:" << total << endl;
        }
};

// 静态数据成员,必须在类外定义
int Student::total;		// 本质:将全局的作用数据修改其作用域

void totalStudentNumber();	
{
      cout << "总人数:" << total << endl;
}


int main()
{
    Student jack;
    
    Student::totalStudentNumber();	// 可以不依赖对象调用
    jack.totalStudentNumber();	// 也可以用类对象调用
    
    return 0;
}


注意:
    1、静态类成员( 静态数据区 )与普通成员存储空间不一样
    2、静态类成员不属于任何一个对象,是共有的,只有一份
    3、静态类方法只能调用其他静态类方法或引用类静态数据,不能调用普通方法和数据(因为后者有归属者,说不定不存在)
    

小补充:当构造函数被private修饰-------设计模式:单例模式
class Node
{
    public:
    	static Node* getInstance();
    
    private:
    	Node();
    
    private:
    	static Node* m_ptr;
};

Node* Node::m_ptr = NULL;

Node::Node()
{
    cout << "123" << endl;
}

Node* Node::getIstance()
{
    if(m_ptr == NULL)
    {
    	m_ptr = new Node;	// 这样设定就是为了只被构造一次
    }
    
    return m_ptr;
}

int main()
{
    Node* n = Node::getInstance();
    cout << n << endl;
    
    return 0;
}

初始化列表

cpp 复制代码
#include <iostream>
using namespace std;

class Score
{
    private:
    	float math;		// 数学成绩
    	float history;	// 历史成绩
    
    public:
    	Score(float m=0, float h=0)
            : math(m), history(h)
        {
        	     
        }
};

class Student
{
    private:
    	int age;			// 普通类成员
    	const string name;	 // const型类成员
    	Score score;		// 类对象成员
    
    public:
    	Student(int a, string n, Score &s)	// & 这里采用引用就只构造一次
            : age(a), name(n), score(s)	// 初始化列表
        {
                
        }
    
    	showInfo() { cout << "数学和历史:" << math << history << endl; }
};


int main()
{
    Score score(98, 89);
    Student student(22, "罗宏斌", score);
    
    student.showInfo();
    
    return 0;
}




const 型类成员和类对象成员必须在初始化列表中进行初始化,为免去记忆,全部在初始化列表中初始化
    
    
    
    
    
类组合
#include <iostream>
using namespace std;

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

	private:
    	int m_AAA;
};

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

	private:
    	int m_A;
};

class B
{
	public:
   		B(int n) : m_B(n) {cout << "B" << endl;}
    	~B() {cout << "~B" << endl;}

	private:
    	int m_B;
};

class C
{
	public:
    	// 不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。
    	C(int x, int y) 
            : b(x), m_C(y) 
        { 
            cout << "C" << endl; 
        }
    
    	~C() {cout << "~C" << endl;}

	private:
    	A a;
    	B b;
    	AAA* aaa;
    	int m_C;
};

int main(int argc, char *argv[])
{
    // 类对象产生时,其构造顺序:
    // 1、先构造成员变量
    // 2、再调用构造函数
    C c(11, 12);

    return 0;
}
相关推荐
星光樱梦9 分钟前
24. 正则表达式
c++
fathing10 分钟前
c# 调用c++ 的dll 出现找不到函数入口点
开发语言·c++·c#
前端青山32 分钟前
webpack指南
开发语言·前端·javascript·webpack·前端框架
nukix1 小时前
Mac Java 使用 tesseract 进行 ORC 识别
java·开发语言·macos·orc
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】内存可见性问题 & volatile
java·开发语言·java-ee
hope_wisdom1 小时前
C++网络编程之SSL/TLS加密通信
网络·c++·ssl·tls·加密通信
erxij1 小时前
【游戏引擎之路】登神长阶(十四)——OpenGL教程:士别三日,当刮目相看
c++·经验分享·游戏·3d·游戏引擎
Lizhihao_1 小时前
JAVA-队列
java·开发语言
林开落L2 小时前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色2 小时前
基于MATLAB边缘检测博文
开发语言·算法·matlab