类是什么
类是一种自定义类型的蓝图,它把数据(成员变量)和行为(成员函数)打包成一个整体。int、double 这样的内置类型描述的是单个值,而类让你把一个完整的概念,比如银行账户、二维坐标点、玩家,建模成一个可以到处传递的值。
其实你早就在使用类了,只是没有自己定义过:std::string 和 vector 容器都是标准库中的类。调用 name.length() 或 v.push_back(3),就是在对象上调用成员函数。现在你将用同样的方式构建自己的类型,然后再学习用构造函数来初始化它们。
定义类和创建对象
类的定义把成员列在花括号之间,并以分号结尾,忘记末尾的 ; 是新手最常见的错误之一。根据类创建的每个对象,都有自己的一份成员变量。
rex 和 luna 是两个独立的对象。修改 rex.name 不会影响 luna.name,每个对象都保存着自己的数据。对对象使用点运算符 . 来访问成员(如果你拿到的是指向对象的指针,就用 ->)。
public 与 private
默认情况下,class 中的一切都是私有的:只有这个类自己的成员函数才能访问。public: 标记让成员对外部代码开放。这种划分是封装的核心:你对外暴露一个安全的接口,把内部数据隐藏起来,使它不会被置于非法状态。
因为 count 是私有的,任何调用方都无法偷偷塞进一个负数或不合理的值,他们必须通过 increment()。value() 参数列表后面的 const 承诺这个函数不会修改对象,这样就能在 const 对象上调用它,同时也向读者表明了意图。
方法的声明与定义
对于小型的类,像上面那样在类内定义方法是可以的。对于较大的类,常见的做法是在类内声明方法,在类外用 ClassName::method 这种作用域语法定义方法体。这样类的定义读起来就像一份接口摘要。
Rectangle:: 前缀告诉编译器这个函数属于哪个类。在这样的定义内部,你仍然直接用成员的名字(width、area())来引用它们,编译器知道它们属于调用该方法的那个对象。
this 指针
在任何非静态成员函数内部,this 都是指向调用该函数的对象的指针。通常你用不到它,因为直接写成员名就已经指向当前对象了。它真正派上用场的时候,是参数遮蔽了成员(两者同名),你必须加以区分。
如果不写 this->,在 setX 中写 x = x; 只会把参数赋值给它自己,成员保持不变,这是一个不声不响的 bug。this->x 让含义变得明确。许多代码库干脆给参数起不同的名字(例如 setX(int newX))来完全避开这个问题,但在真实的代码中,你会经常看到 this->。
常见错误
有几个关于类的陷阱,总是反复让人中招:
- 漏掉末尾的分号。 类的定义以
};结尾。漏掉;,你会得到一大堆令人困惑的错误,它们指向的是类后面的代码,而不是类本身。 - 忘记初始化成员。
int和double这样的内置类型成员不会被自动清零。读取未初始化的成员属于未定义行为。给成员设置默认值(int count = 0;),或者在构造函数中初始化它们。 - 从外部访问私有成员。 对私有成员写
c.count = 5;会编译报错,应该改为通过公有方法访问。这正是封装在按预期发挥作用。 - 把类和对象搞混。
Dog.bark();是错的,Dog是类型。方法要在对象上调用:rex.bark();。
// Uninitialized member - reading 'age' is undefined behavior:
class Cat {
public:
int age; // no default value
};
Cat c;
std::cout << c.age; // garbage value, not 0
下一篇:构造函数
创建对象后再逐个手动设置成员,比如 rex.name = ...; rex.age = ...;,既繁琐又容易遗漏,而成员未初始化的问题正是这样产生的。下一篇讲解构造函数:一种在对象创建时自动运行的特殊函数,它能保证每个对象一开始就处于合法状态,还能用 Dog rex("Rex", 4); 这样简洁的一行语法来创建对象。
常见问题
C++ 中类和对象有什么区别?
类是蓝图,它描述了一个类型拥有哪些数据(成员变量)和行为(成员函数)。对象是根据这张蓝图构建出来的具体实例。class Dog { ... }; 只定义一次类型;Dog rex; 则创建一个可以实际使用的 Dog。一个类可以产生许多相互独立的对象。
C++ 中 class 和 struct 有什么区别?
从技术上讲,只有默认的访问级别不同:class 的成员默认是 private,struct 的成员默认是 public。两者都可以有成员函数、构造函数和继承。按照惯例,struct 用于单纯的数据集合,class 用于拥有行为、需要保护不变量的类型。
C++ 类中的 this 指针有什么作用?
在成员函数内部,this 是指向调用该函数的对象的指针。可以用它来区分同名的参数和成员(this->x = x;),或者返回当前对象。正常访问成员时很少需要它,直接写 x 就已经是指当前对象的 x。