C++学习10

94 阅读5分钟

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}

其中:   

  1.   capture-list 用于捕获外部变量,可以是按值捕获(以值传递方式使用变量)或按引用捕获(以引用方式使用变量)。如果不需要捕获任何外部变量,可以省略该部分。
  2. params 是函数参数列表。可以使用与普通函数相同的语法定义参数。
  3. return-type 是**返回值类型,**可以省略,编译器可以推导出返回值类型。
  4. {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。

成员初始化列表在几种情况下非常有用:

  1. 对于具有常量成员变量或引用类型成员变量的类,必须在构造函数中进行初始化,因为它们不能在后续的赋值语句中修改。
  2. 当类有多个构造函数时,可以在初始化列表中为各个构造函数共享的成员变量设置初始值,避免在每个构造函数中重复编写初始化代码。
  3. 当类具有复杂对象类型的成员变量时,使用初始化列表可以直接调用成员对象的特定构造函数,而不是先默认构造再通过赋值运算符进行赋值操作,提高效率。

上一篇文章也有学习到。(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;
}