1.1 mutable
#include <iostream>
#include <string>
class Entity
{
private:
std::string m_Name;//类成员变量的声明,用于在类中存储实体的名称。
//声明了一个名为 m_Name 的 std::string 类型的成员变量。
//std::string 是 C++ 标准库中表示字符串的类,可以存储任意长度的文本。
mutable int m_DebugCount = 0;
public:
const std::string& GetName() const //可修改特定成员变量
{
m_DebugCount++;
return m_Name;
}
};
int main()
{
const Entity e;//常量对象,在 const 对象上只能调用常量成员函数,而无法调用非常量成员函数。
e.GetName();
std::cin.get();
}
解析:代码定义了一个名为 Entity 的类,该类包含一个私有成员变量 m_Name(表示实体的名称)和一个可变成员变量 m_DebugCount(用于调试目的)。
类中还声明了一个公共方法 GetName(),该方法返回一个指向实体名称的常量字符串的引用。此方法被声明为 const,表示它不会修改对象的任何成员变量(包括 m_Name 和 m_DebugCount),但是它可以更改 m_DebugCount 成员变量的值,因为它被声明为 mutable。
在方法内部,我们增加了 m_DebugCount 的值,以便我们在每次调用 GetName() 方法时都可以追踪调用次数。然后,我们返回实体名称的引用,以使其可以在需要时修改,同时保持 GetName() 方法的常量特性。
const std::string& GetName() const
函数的返回类型是 const std::string&,表示返回一个对 std::string 类型的常量引用。这意味着函数返回一个指向实体名称的引用,并且该引用是不可修改的,即外部代码无法通过该引用来修改实体名称。
函数后面的 const 关键字表示该函数是一个常量成员函数,不会修改类的任何成员变量。在常量成员函数中,只能调用其他常量成员函数,而不能调用非常量成员函数。
const 还可以用在 lambda
Lambda 是 C++11 引入的一种匿名函数实现方式,它可以用一种简洁的语法创建一个函数对象。
[capture-list](params) -> return-type {body}
其中:
- capture-list 用于捕获外部变量,可以是按值捕获(以值传递方式使用变量)或按引用捕获(以引用方式使用变量)。如果不需要捕获任何外部变量,可以省略该部分。
- params 是函数参数列表。可以使用与普通函数相同的语法定义参数。
- return-type 是**返回值类型,**可以省略,编译器可以推导出返回值类型。
- {body} 中是函数实现的代码块。
Lambda 表达式可以捕获当前作用域内的变量,并在代码块中访问这些变量。
实例:
#include <iostream>
#include <string>
class Entity
{
private:
std::string m_Name;
mutable int m_DebugCount = 0;
public:
const std::string& GetName() const //可修改特定成员变量
{
m_DebugCount++;
return m_Name;
}
};
int main()
{
const Entity e;
e.GetName();
int x = 8;
auto f = [=]() mutable
{
/* int y = x;
y++;
std::cout << y << std::endl;*/
x++;
std::cout << x << std::endl;
};
f();
std::cin.get();
}
结果:
1.2 构造函数初始化列表(Constructor initialization list )
C++ 中的成员初始化列表允许在构造函数中对类成员变量进行初始化.
class MyClass {
private:
int m_Value;
public:
MyClass(int value) : m_Value(value) // 构造函数初始化列表
{
// 构造函数的其他代码
}
};
解析:
MyClass类有一个私有成员变量m_Value。使用参数 value 来初始化 m_Value。
成员初始化列表在几种情况下非常有用:
- 对于具有常量成员变量或引用类型成员变量的类,必须在构造函数中进行初始化,因为它们不能在后续的赋值语句中修改。
- 当类有多个构造函数时,可以在初始化列表中为各个构造函数共享的成员变量设置初始值,避免在每个构造函数中重复编写初始化代码。
- 当类具有复杂对象类型的成员变量时,使用初始化列表可以直接调用成员对象的特定构造函数,而不是先默认构造再通过赋值运算符进行赋值操作,提高效率。
上一篇文章也有学习到。(but 不是很理解以上三条的意思)
注意:在给 Entity 类的构造函数添加成员初始化列表时,如果某个成员变量已经在类的成员声明中进行了初始化(例如 Example m_Example;),那么在构造函数的成员初始化列表中再次对该成员变量进行初始化,实际上会调用相应类型的默认构造函数创建第二个临时对象,然后将这个临时对象赋值给成员变量。
#include <iostream>
#include <string>
class Example
{
public:
Example()
{
std::cout << "Created Entity!" << std::endl;
}
Example(int x)
{
std::cout << "Created Entity with " << x << "!" << std::endl;
}
};
class Entity
{
private:
std::string m_Name;
Example m_Example; //成员变量Example型
public:
Entity()
{
m_Name =std::string( "Unknown" );
m_Example = Example(8); //新的实例 2 obj 并把它赋值给m_Example
}
Entity(const std::string& name)
: m_Name(name)
{
}
const std::string& GetName() const { return m_Name; }
};
int main()
{
Entity e0;
/* std::cout << e0.GetName() << std::endl;
Entity e1("Cherno");
std::cout << e1.GetName() << std::endl;*/
std::cin.get();
}
代码中的:
class Entity
{
private:
std::string m_Name;
Example m_Example; //成员变量Example型
public:
Entity()
{
m_Name =std::string( "Unknown" );
m_Example = Example(8); //新的实例 2 obj 并把它赋值给m_Example
}
Entity(const std::string& name)
: m_Name(name)
{
}
const std::string& GetName() const { return m_Name; }
};
解析:Entity 类的构造函数中使用了成员初始化列表 Entity() : m_Name("Unknown") 对 字符串成员变量 m_Name 进行了初始化。而在 Entity 类的成员声明中,又有一个 Example 类型的成员变量 m_Example,它会在默认构造函数中被初始化。
创建 Entity 类的实例对象 e0 时,首先会调用 Example 类的默认构造函数,输出 "Created Entity!",并创建一个临时的 Example 类对象。然后,在 Entity 类的构造函数体中,通过赋值运算符将这个临时对象的值赋给 m_Example 成员变量。
解决方法:移动至初始化列表中
#include <iostream>
#include <string>
class Example
{
public:
Example()
{
std::cout << "Created Entity!" << std::endl;
}
Example(int x)
{
std::cout << "Created Entity with " << x << "!" << std::endl;
}
};
class Entity
{
private:
std::string m_Name;
Example m_Example; //成员变量Example型
public:
Entity()
: m_Example(Example(8))
{
m_Name =std::string( "Unknown" );
//m_Example = Example(8); //新的实例 2 obj 并把它赋值给m_Example
}
Entity(const std::string& name)
: m_Name(name)
{
}
const std::string& GetName() const { return m_Name; }
};
int main()
{
Entity e0;
std::cin.get();
}
结果:
1.3 C++ 中的三元操作符( ternary operator )
C++中的三元操作符是一种条件运算符,也称为条件表达式。它的语法形式如下: 条件 ? 表达式1 : 表达式2
1.4 C++ 创建并初始化变量
Entity entity("cherno"); e = &entity; 这样创建的对象是在栈上的。
Entity* e = new Entity("Cherno") ; ----delete e; 这样创建的对象是在堆上的。
#include <iostream>
#include <string>
using String = std::string;
class Entity
{
private:
String m_Name;
public:
Entity() : m_Name(" Unknown "){}
Entity(const String& name) : m_Name(name){}
const String& GetName() const { return m_Name;}
};
int main()
{
Entity* e;
{
Entity entity(" Cherno ");
e = &entity;
std::cout << entity.GetName() << std::endl;
}
std::cin.get();
}
结果都是
通过new,创建在堆上,记得用delete
#include <iostream>
#include <string>
using String = std::string;
class Entity
{
private:
String m_Name;
public:
Entity() : m_Name(" Unknown "){}
Entity(const String& name) : m_Name(name){}
const String& GetName() const { return m_Name;}
};
int main()
{
Entity* e;
{
Entity* entity = new Entity(" Cherno ");
e = entity;
std::cout << (*entity).GetName() << std::endl;
//entity->GetName()
}
std::cin.get();
delete e;
}