C++面向对象(一):类、封装、成员变量初始化
C++中的类
C++可以使用 class、struct 来定义类。
class是C++特有的,C里面没有,至于为什么要保留sturct,大概是为了让开发者更顺滑的从C过渡到C++吧。
#include <iostream>
using namespace std;
// struct Person {
class Person {
public:
// 属性(成员变量)
int m_age;
const char *m_name;
// 自定义构造函数,进行初始化,可以重载
// this可以省略,在编译时会自动加上,指向对象
Person () {
this->m_name = "卢本伟";
m_age = 666;
}
// 自定义构造函数,简写
Person (const char *name, int age) :m_name (name), m_age (age) {}
// 方法(成员函数)
void say () {
cout << "my name is " << this->m_name << ", I am " << m_age << " years old." << endl;
cout << m_name << " NB!" << endl;
}
//析构函数
// 在里面释放一些资源
~Person () {
cout << this->m_name << "已经被释放" << endl;
}
};
与C 相比,C++中 struct 定义的类里面可以定义函数,在C中,可以这样模拟成员函数:
void test() {};
struct Person {
void(*say)() = test;
};
C++中利用类创建一个对象,并调用属性与方法:
void test () {
// 利用类创建对象
Person person;
// Java\Js :
// Person person = new Person();
// OC :
// Person *person = [Person new];
//访问属性与方法
person.m_name = "伞兵一号";
person.m_age = 666;
person.say ();
cout << "**********************" << endl;
// 把person对象的地址值给指针,所以指针对象的类型是Person
Person *p = &person;
p->m_name = "伞兵二号";
p->m_age = 233;
p->say ();
cout << "**********************" << endl;
{
// 直接创建一个实例,再对实例初始化
// 这里在栈上实例化,没有任何东西就调用默认构造函数
Person lubenwei;
lubenwei.m_age = 666666;
lubenwei.say ();
}
cout << "**********************" << endl;
{ // 堆上构建
// new返回一个指针
Person* lu = new Person ("伞兵三号", 250);
// 指针调用
lu->say ();
// 对象对用
//(*lu).say();
delete lu;
}
}
struct和class的区别在于权限:
struct的默认成员权限是public,外面所有人可以直接访问。
class的默认成员权限是private,只有类内部可以访问。
这两个是一样的:
class Person {
//public:
// 属性(成员变量)
int m_age;
const char *m_name;
// 方法(成员函数)
void say () {
cout << m_name << "NB!" << endl;
}
};
struct Person {
private:
// 属性(成员变量)
int m_age;
const char *m_name;
// 方法(成员函数)
void say () {
cout << m_name << "NB!" << endl;
}
};
C++中一般创建类还是使用class较多。
class Person {
public:
int m_age;
void say() {
cout << m_age << endl;
}
};
void test () {
Person person;
person *p = &person;
p->m_age = 250;
p->say();
}
上面这段代码中的person对象、p指针都存在于函数的栈空间中,自动分配和回收。
x64环境下,这里的person对象占4个字节(只有一个int属性),p指针占8个字节(指向person的地址值),局部变量总共占用12个字节。
struct Car {
int m_price;
};
class Car {
public:
int m_price;
};
int main() {
Car car;
car.m_price = 1;
getchar();
return 0;
}
这里的car对象就只有一个成员,并且占用4个字节,所以car对象的地址值就是m_price的地址值,可以看一下这里struct和class生成的汇编,除了地址之外,两句是一模一样的,所以这两个实际上确实只有权限区别。
00007FF640DA60CF mov dword ptr [rbp+4],1
00007FF7694360CF mov dword ptr [rbp+4],1
每次创建成员变量都会分配内存,而函数在内存中只有一份,不管创建几个对象都只会call那个相同的函数地址,执行相同的代码,并且由于编译器优化的原因,函数没有调用时是不被编译的,相当于不存在。
声明和实现分离
开发时会将类的声明和实现分离。
声明放入头文件:
// 放入.h文件
class Person {
private:
int m_age;
public:
// 一些声明
Person();
void setAge(int age);
int getAge();
~Person();
};
实现在cpp文件:
#include "Person.h"
// 加一个域限定符::
void Person::setAge(int age) {
m_age = age;
}
int Person::getAge() {
return m_age;
}
Person::Person(){
m_age = 0;
}
Person::~Person() {
}
封装
成员变量私有化,提供公共的getter和setter给外界访问成员变量
为了防止外部的随意篡改,而在类内部进行处理:
class Person {
int m_id = 1;
int m_age = 2;
int m_height = 3;
void display() {
cout << "m_id is " << m_id << endl;
cout << "m_age is " << m_age << endl;
cout << "m_height is " << m_height << endl;
}
public :
// 赋值
void setAge(int age) {
if (age <= 0) {
m_age = 666;
} else {
m_age = age;
}
}
// 取值
int getAge() {
return m_age;
}
};
int main() {
Person person;
person.setAge(-666);
int age = person.getAge();
cout << age << endl;
getchar();
return 0;
}
成员变量初始化
没有自定义构造函数时:
struct Person {
int m_age;
};
// 全局区:成员变量初始化为0
// 全局区的变量都会初始化为0
Person g_person;
int main() {
// 栈空间:没有初始化成员变量,会报错
// Person person;
// 堆空间:没有初始化成员变量
Person *p0 = new Person;
// 堆空间:成员变量初始化为0
Person *p1 = new Person();
// 堆空间:没有初始化成员变量
Person *p2 = new Person[6];
// 堆空间:6个Person对象的成员变量全部初始化为0
Person *p3 = new Person[6]();
// 堆空间:6个Person对象的成员变量全部初始化为0
Person *p4 = new Person[6]{};
getchar();
return 0;
}
但是,如果定义了构造函数,除了全局区,其他内存空间的成员变量默认都不会被初始化,需要开发人员手动初始化。
快捷的初始化所有对象:
struct Person {
int m_age;
Person () {
// 希望创建的所有对象的成员变量全部初始化为0
memset(this, 0, sizeof(Person));
}
};

本文介绍了C++中的面向对象特性,包括类的声明与实现,封装原则以及成员变量的初始化。讲解了class与struct的区别,强调了封装的重要性,并探讨了如何通过构造函数确保成员变量的初始化。
75万+

被折叠的 条评论
为什么被折叠?



