5. 作用域限定符 ::
5.1 名字空间(掌握)
名字空间是一种代码的层级划分。
#include <iostream>
using namespace std;
// C++课程中几乎所有的类型(不包括基本数据类型)都在std中
int a = 1;
// 新建一个名字空间
namespace my_space {
int a = 3;
string s = "哈哈哈";
}
namespace my_space2 {
int a = 4;
string s = "嘿嘿嘿";
}
// 使用自己的名字空间
using namespace my_space2;
int main()
{
int a = 2;
std::cout << "你好" << std::endl;
cout << a << endl; // 2
cout << ::a << endl; // 1
// 访问my_space的内容
cout << my_space::a << my_space::s << endl;
// 访问my_space2的内容
cout << my_space2::a << s << endl;
return 0;
}
5.2 类内声明,类外定义(重点)
函数是可以声明定义分离的,成员函数也可以声明定义分离,把成员函数的声明放置在类内,把成员函数的定义放置在类外,因为定义在类外,所以需要类名::来制定定义的函数是哪个类的。
#include <iostream>
using namespace std;
class Student
{
private:
string name;
public:
// 类内声明
Student(string n);
string get_name();
void set_name(string n);
};
// 类外定义
Student::Student(string n)
{
name = n;
}
string Student::get_name()
{
return name;
}
void Student::set_name(string n)
{
name = n;
}
int main()
{
Student s("张三");
s.set_name("张三丰");
cout << s.get_name() << endl;
return 0;
}
5.3 配合静态使用
在后续static关键字中讲解。
6. this关键字
6.1 概念(掌握)
this在类中表示一个指针:this指针,是一种特殊的指针,保存了当前类对象的首地址(指向了当前类的对象)。、
#include <iostream>
using namespace std;
class Student
{
private:
string name;
public:
Student(string n):name(n)
{
cout << this << endl;
}
string get_name()
{
cout << this << endl;
return name;
}
void set_name(string n)
{
cout << this << endl;
name = n;
}
};
int main()
{
Student s("张三");
cout << &s << endl;
s.set_name("张三丰");
cout << s.get_name() << endl;
cout << endl;
Student* s2 = new Student("李四");
cout << s2 << endl;
cout << s2->get_name() << endl;
return 0;
}
6.2 调用成员(掌握)
结论:成员必须由对象调用。
#include <iostream>
using namespace std;
class Student
{
private:
string name;
public:
Student(string n)
{
this->name = n;
cout << this->get_name() << endl;
}
string get_name()
{
return this->name;
}
void set_name(string n)
{
this->name = n;
}
};
上面的代码中,所有在类内调用成员的位置,如果程序员不写this指针(实际上没有必要手写,比较繁琐),编译器都会在成员调用之前添加this指针。
6.3 区分重名的成员变量与局部变量(掌握)
#include <iostream>
using namespace std;
class Student
{
private:
string name;
public:
Student(string name)
{
this->name = name;
}
string get_name()
{
return name;
}
void set_name(string name)
{
this->name = name;
}
};
int main()
{
Student s("Tom");
cout << s.get_name() << endl;
s.set_name("Jerry");
cout << s.get_name() << endl;
return 0;
}
6.4 链式调用(熟悉)
结论:如果一个成员函数的返回值是当前类型的引用,说明这个函数支持链式调用,return的内容一定是*this。
#include <iostream>
using namespace std;
class Value
{
private:
int value;
public:
Value(int value)
{
this->value = value;
}
Value& add(int value)
{
this->value += value;
return *this;
}
int get_value()
{
return value;
}
};
int main()
{
Value v1(0);
// 普通的调用方式:分步操作
v1.add(1);
v1.add(2);
v1.add(4);
v1.add(7);
cout << v1.get_value() << endl; // 14
cout << endl;
Value v2(0);
// 链式调用
cout << v2.add(1).add(2).add(4).add(7).get_value() << endl; // 14
cout << v2.get_value() << endl; // 14
return 0;
}
7. static关键字
7.1 静态局部变量(掌握)
使用static修饰的局部变量就是静态局部变量,所在的函数第一次被调用时创建,直到程序运行结束销毁,所有的对象共用这个一个静态局部变量。
#include <iostream>
using namespace std;
class Test
{
public:
void test_static()
{
int a = 1;
static int b = 1; // 局部静态变量
cout << a++ << endl;
cout << b++ << endl << endl;
}
};
int main()
{
Test t1;
Test t2;
t1.test_static();
t2.test_static();
t1.test_static();
return 0;
}
7.2 静态成员变量(掌握)
使用是static关键字修饰的成员变量就是静态成员变量。
静态成员变量具有以下特点:
1. 非const修饰的静态成员变量不能在类内初始化,必须在类外初始化。
2. 同一个类的所有对象共享一份静态成员变量。
3. 静态成员变量可以直接通过类名调用,无需关联任何对象,因为静态成员变量在程序执行时创建,在程序结束时销毁。
#include <iostream>
using namespace std;
class Test
{
public:
int a = 1; // 成员变量
static int b; // 静态成员变量
};
int Test::b = 1; // 类外初始化
int main()
{
// 通过类名直接调用静态成员变量
cout << Test::b << " " << &Test::b << endl;
Test t1;
Test t2;
cout << t1.a++ << " " << &t1.a << endl;
cout << t2.a++ << " " << &t2.a << endl;
cout << t1.b++ << " " << &t1.b << endl;
cout << t2.b++ << " " << &t2.b << endl;
return 0;
}
7.3 静态成员函数(掌握)
使用static修饰的成员函数就是静态成员函数,静态成员函数具有以下特点:
1. 没有this指针,因此不能调用非静态成员。
2. 如果静态成员函数声明与定义分离,static只需要写在声明处即可。
3. 除了可以使用对象调用外,还可以直接通过类名::调用,更加推荐后者。
#include <iostream>
using namespace std;
class Test
{
public:
int a = 1;
static int b;
static void func(); // 静态成员函数
};
int Test::b = 1;
void Test::func() // 类外定义
{
// cout << a << endl; 错误
cout << b << endl;
}
int main()
{
Test t;
t.func();
Test::func();
return 0;
}
7.4 单例模式(了解)
模式设计(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
单例 = 单实例
实例 instance = 对象 object
单例模式可以让类的对象全局创建时保持一个。
基于指针的单例模式(非完全版):
#include <iostream>
using namespace std;
/**
* @brief The Singleton class 单例模式的类
*/
class Singleton
{
private: // 构造函数私有化防止外部调用
Singleton(){}
Singleton(const Singleton&){}
static Singleton* instance; // 类内的对象,即单例
public:
static Singleton* get_instance()
{
if(instance == NULL)
instance = new Singleton;
return instance;
}
};
Singleton* Singleton::instance = NULL;
int main()
{
Singleton* s1 = Singleton::get_instance();
cout << s1 << endl;
Singleton* s2 = Singleton::get_instance();
cout << s2 << endl;
return 0;
}
基于引用的单例模式:
#include <iostream>
using namespace std;
/**
* @brief The Singleton class 单例模式的类
*/
class Singleton
{
private: // 构造函数私有化防止外部调用
Singleton(){}
Singleton(const Singleton&){}
public:
static Singleton& get_instance()
{
static Singleton instance;
return instance;
}
};
int main()
{
Singleton& s1 = Singleton::get_instance();
Singleton& s2 = Singleton::get_instance();
cout << &s1 << " " << &s2 << endl;
return 0;
}
8. const关键字
8.1 修饰成员函数(掌握)
const修饰的成员函数,表示常成员函数,可以调用非const的成员变量,但是不能修改数值,不能调用非const的成员函数。
如果常成员函数的声明与定义分离,const在声明和定义处都要使用。
#include <iostream>
using namespace std;
class Test
{
private:
string name;
public:
void set_name(string name)
{
this->name = name;
}
string get_name() const; // 常成员函数
void test_const() const // 常成员函数
{
// set_name("哈哈哈"); 错误
cout << get_name() << endl;
cout << name << endl;
// name = "你好"; 错误
}
};
string Test::get_name() const // 类外定义
{
return name;
}
int main()
{
Test t;
t.set_name("再见");
t.test_const();
return 0;
}
建议只要成员函数不修改属性值就使用const修饰,以提升代码的安全性,例如getter等。
8.2 修饰对象(掌握)
const修饰对象表示该对象是常量对象,这样的对象的成员变量数值不可变,不能调用任何非const修饰的成员函数。
#include <iostream>
using namespace std;
class Test
{
public:
// string name = "张三"; // 直接初始化可以
string name;
// Test(string name)
// {
// this->name = name; // 构造函数函数体初始化可以
// }
Test(string name):name(name){}
void set_name(string name)
{
this->name = name;
}
string get_name() const
{
return name;
}
};
int main()
{
// const可以放在类型前后
Test const t1("张三");
// t1.set_name("你好"); 错误
const Test t2("李四");
// t2.name = "你好"; 错误
cout << t1.get_name() << endl;
cout << t2.get_name() << endl;
return 0;
}
8.3 修饰成员变量(掌握)
const修饰的成员变量表示常成员变量,这样的成员变量值不允许被修改。
常成员变量的初始化方式有两种:
- 直接初始化
- 构造初始化列表(优先级更高)
#include <iostream>
using namespace std;
class Test
{
public:
const string name = "张三"; // 直接初始化
Test(string name):name(name) // 构造初始化列表
{}
// Test(string name)
// {
// this->name = name; 错误
// }
void set_name(string name)
{
// this->name = name; 错误
}
string get_name() const
{
return name;
}
};
int main()
{
Test t("王五");
cout << t.get_name() << endl;
return 0;
}
8.4 修饰局部变量
表示局部变量不可被修改,常见于const修饰引用参数。
代码略。
8.5 constexpr 常量表达式(熟悉)
constexpr是比const更严谨的关键字,表示编译期确定的常量值。
#include <iostream>
using namespace std;
class Test
{
public:
constexpr static int a = 1; // a=1在编译期确定
// constexpr int b = 2; 错误
const int c = 3;
};
在上面的例子中,a不需要配合任何对象使用,而对象是在程序运行期间创建的,因此a可以被constexpr修饰,表示在编译期确定;反之b需要在对象创建之后才能创建,因此不能被constexpr修饰。
被constexpr修饰的内容表示在编译期间可以确定,C++中部分代码是需要在编译期间确定。
#include <iostream>
#include <array> // 后面要学习的一个头文件
using namespace std;
// 表示是否可以在编译期间计算出返回值
constexpr int calc_len(int i)
{
return i+5; // 随便写的计算规则
}
int main()
{
// 5表示创建的arr对象的长度,必须在编译期间确定
array<int,5> arr;
// 编译期间可以计算出结果为6,正确
array<int,calc_len(1)> arr2;
int i = 1;
// 编译期间无法计算出最后结果,报错
// array<int,calc_len(i)> arr3; 错误
return 0;
}
标签:Singleton,const,name,int,成员,C++,关键字,string
From: https://blog.csdn.net/2301_77143270/article/details/142620540