在C++中类和结构体已经没有很大得差别了,类可以做到得事,结构体也能做。唯一的不同就是类成员的默认权限是private,结构体的默认权限是public
一个简单类的使用案例
#include <iostream> #include <string> class Person { public: int m_age; std::string m_name; inline void m_printf() { std::cout << "名字:" << m_name << " 年龄:" << m_age << std::endl; } }; int main(void) { Person p = {12, "小王"}; p.m_printf(); Person p1; p1.m_age = 20; p1.m_name = "小明"; p1.m_printf(); Person p2; Person* pp = &p2; pp->m_age = 22; pp->m_name = "芜湖"; pp->m_printf(); return 0; }
以上,介绍了一个类的基本定义,基本声明与定义,以及不同的初始化方式和使用成员的方法。
类的this指针
内存空间一般分四种:
1. 栈空间:每调用一个函数,就会为其分配一段连续的内存空间(main函数也一样)。函数调用完毕时回收。
2. 堆空间:new出来的内存空间,需要手动释放。
3. 代码区:存放代码的地方,函数代码都在这里。
3. 全局区(数据段):存放全局变量。(static修饰或者在函数外部修饰的变量)
所以,有个问题就是,既然类中的函数在代码区,而类中的变量在栈空间或者堆空间,那么类成员函数内部是怎么做到不用传参就可以直接使用类成员变量的呢?(看上面的一个例子,函数m_printf()没有接受参数,直接使用了m_age和m_name)
答案就是:this指针的隐式使用。让函数使用其他空间的变量,要么传值,要么传地址。C++的做法就是,this代表类的对象的首地址,传递给类成员函数的内部使用。
class Person { public: int m_age; std::string m_name; inline void m_printf() { std::cout << "名字:" << this->m_name << " 年龄:" << this->m_age << std::endl; } };
通常情况下,this可以省略。
构造函数和析构函数
构造函数:
1. 在对象创建时自动调用,一般用于对象的初始化工作
2. 函数名与类名同名,无返回值(void也不写),可以重载
3. 默认的构造函数是无参的,一旦自定义了构造函数,就必须用其中的一种来初始化
4. 通过malloc分配的对象不会调用构造函数
析构函数:
1. 在对象销毁前自动调用,用于一些清理工作(如堆空间的释放,指针清空等)
2. 通过malloc分配的对象,free时不会调用析构函数
#include <iostream> #include <string> class Person { private: int m_age; std::string m_name; public: Person(int age, std::string name) : m_age(age), m_name(name) { std::cout << "Do nothing!" << std::endl; } ~Person() { std::cout << "Do nothing!" << std::endl; } inline void m_printf() { std::cout << "名字:" << m_name << " 年龄:" << m_age << std::endl; } }; int main(void) { Person p = Person(12, "hh"); p.m_printf(); return 0; }
值得一提的是,构造函数提供了一种更为便捷的初始化类成员变量的方式,这叫做:初始化列表。特点:
1. 只在构造函数里有
2. 初始化顺序,只跟成员变量的声明顺序有关,与初始化列表顺序无关
构造函数的相互调用
class Person { private: int m_age; std::string m_name; public: Person() : Person(10, "hh") {} Person(int age, std::string name) : m_age(age), m_name(name) { std::cout << "Do nothing!" << std::endl; } };
值得注意的是,构造函数的相互调用,必须在初始化列表中。这样确保了优先调用构造函数。