本文深入探讨C++中的类与对象概念,包括类的定义、成员变量与函数、访问控制、封装、this指针的使用,以及类的头文件与源文件分离实践。适合初学者和进阶开发者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


1类和成员变量

类class
类(class),是对结构体 struct的增强,也是用于自定义类 型的。

struct Object
{
int a;
int b;
double c;
double d;
};
classObject
{
public:
int a;
int b;
double c;
double d;
};
①将关键字struct改为class
② 增加访问修饰符public

类class
使用class关键字,添加public修饰符:
class Object
{
public:
int a;
int b;
double c;
double d;
};
仍然将a,b,c,d称为成员变量。

类class
以下为访问其 成员变量 的方法:(和struct时代完全相同)
Object obj;
obj.a = 11;
obj.b = 12;
obj.c = 13.0;
obj.d = 14.0;
Object* p = &obj; // 指针类型
printf("%d, %d, %lf, %lf\n", p->a, p->b, p->c, p->d);

访问修饰符
访问修饰符: public, private ,用于表示类的成员是否允许被外部访问。 public: 公开的,所列的成员可被外部访问 private: 私有的,所列的成员不可以被外部访问
例:
class Object
{
public:
int a;
int b;
private:
double c;
double d;
};
则,a,b允许被外部访问。c,d不允许被外部访问。

访问修饰符
Object obj;
obj.a = 11;
obj.b = 12;
obj.c = 13.0; // 编译错误!private成员!
obj.d = 14.0; // 编译错误! private成员!
Object* p = &obj;
p->a = 11;
p->c = 13.0; // 编译错误!private成员!

访问修饰符
语法:public/private后面要加冒号。
一般将public/private顶格书写,不缩进。每个一行。
如,
class Object
{
public :
private:
private:
public:
};

访问修饰符
语法:每个成员变量只受前一个修饰符的限制, 例如,
class Object
{
public:
private:
public:
public:
int a;
int b;
private:
public:
private:
double c;
double d;
};

内存视图
对于class类型的内存视图,原理上仍然和struct一样:各 成员依次排列在内存里。
由于class的成员较为复杂,一般不再强调内存视图,只要 记住原理就可以了。

小结
class在struct的基础上,增加了“访问修饰符”的语法, 使得外部不能任意地访问class内的成员变量。
只有被public修饰的成员变量,才可以被外部访问。
而被private修饰的成员变量,是私有的,不能被外部访问。

2成员函数及this指针的意义

成员函数
定义在class内的函数,称为该类的成员函数。
(成员变量,成员函数,它们统称为类的成员
class Object
{
public:
int x;
int y;
void Test()
{
printf(“hello,world!\n”);
}
};

成员函数
成员函数的访问:也是使用.号或 ->
Object obj;
obj.Test(); // 点号 .
Object* p = &obj;
p->Test(); // 箭头 ->

成员函数
同样受访问修改符的限制,被public修饰的可以被外部访问,被private修饰的则不能被外部访 问。
class Object
{
public:
int x;
int y;
void Test()
{
printf(“hello,world!\n”);
}
private:
void Test2() // 该函数被private修饰,不能被外部访问
{
printf(“I am a private function!\n”);
}
};

this指针
要在Test()函数中,将x,y打印出来?怎么做?
class Object
{
public:
int x;
int y;
void Test()
{
// 打印x, y
}
};
Object obj;
obj.Test(); // 已经定义了一个obj对象, 如果在Test函数里把 x,y打印出来?

this指针
一种办法:
class Object
{
public:
int x;
int y;
void Test(Object* that)
{
printf(“x=%d, y=%d\n”, that->x, that->y);
}
};
obj.Test(&obj);

this指针
另一种办法:使用this指针
class Object
{
public:
int x;
int y;
void Test()
{
printf(“x=%d, y=%d\n”, this->x, this->y);
}
};
obj.Test();
// 当Test被调用时,已经把对象obj的指针传给它了。
// 编译器内部就是这么实现的,没必要再画蛇添足地传一个指针给它

this指针
使用this指针,可以直接访问本类的其他成员(变量,函数),不受 public/private的限制。
class Object
{
public:
int x;
int y;
public:
int Add()
{
return this->x + this->y; // 用this->调用其他成员
}
void Test()
{
printf("Sum: %d \n ", this->Add()); // 用this->调用其他成员
}
};

this指针
使用this指针时,不受public/private的限制:
class Object
{
private: // x,y是private的, 但用this->可以访问
int x;
int y;
public:
int Add()
{
return this->x + this->y; // 用this->调用其他成员
}
};
可以理解为:从内部访问其他成员时,不受public/private限制

深入理解this指针
测试this指针的值
class Object
{
public:
int x;
int y;
void Test()
{
printf(“this : %p \n”, this);
}
};
Object obj;
printf(“obj: %p \n”, &obj);
obj.Test();
观察: this是否就是对象obj的地址

小结

  1. 成员函数:定义在class内的函数
  2. 成员函数的调用:也是仍然点号或箭头,也受 public/private 的限制
  3. 使用隐含的this指针,来访问本对象的成员。 this指针 指向了对象自己。
    注:this指针是在形式上做了一个简化,使得用户少传一个 对象的指针作为参数。

补充
成员变量在位置上可以列在成员函数之后
注:this指针是在形式上做了一个简化,使得用户少传一个 对象的指针作为参数。

3名字覆盖问题与命名规范

this->是可以省略的
为了让代码更简洁,this->是可以省略的。编译器会自己给它加上this->。
class Object
{
public:
int x;
int y;
public:
int Add()
{
return x + y; // 相当于 this->x + this->y
}
void Test()
{
printf("Sum: %d \n ", Add()); // 相当于this->Add()
}
};

重名问题:就近原则
(1) 在成员函数里:当局部变量与成员变量重名时,该变量指向的是局 部变量。
class Object
{
public:
int x; // 成员变量
void Test(int x)
{
printf(“x = %d \n”, x);// 最近的:函数内定义的x
}
};
如果要指定成员变量x,则必须加上 this->的限定

重名问题:就近原则
(2) 在成员函数里,当成员变量与全局变量重名时,该变量指向 的是成员变量。
int x = 10; // 全局变量
class Object
{
public:
int x;
void Test(int)
{
printf(“x = %d \n”, x);// 最近的x:成员变量x
}
};
注:如果要指定全局变量x,则必须加上::x

重名问题: “就近原则”
(3) 在成员函数与全局函数重名时,默认指成员函数
void Sum(int x, int y)
{
return x + y;
}
class Object
{
public:
void Sum(int x, int y)
{
return x + y;
}
void Test()
{
printf(“x = %d \n”, Sum(10,11));// 最近的x:成员变量x
}
};
注:::全局符号, this-> 成员

命名规范
类名:每个单词的首字母大写。一般用名词形式。

Circle
GoodObject
HighSchool
StringList
MemoryPool
VeryLargeBuffer
显然,所有命名的一个基本要求:顾名思义,通过名字,能够反映其意义
例如,如果你给一个表示矩形的类命名为Circle,那就是个非常不恰当的 名字。

命名规范
成员函数:每个单词的首字母大写。一般用动词形式。
例如
Open 打开
Close 关闭
Add 添加
Remove 删除
SendMessage 发送消息
RecvMessage 接收消息
可以发现函数名的特点
(1) 通常是成对出现的, Find()
(2) 常用函数名就是那么多,大家一见到就能知道它是干什么的

命名规范
成员变量:小写开头,第二个单词开头大写。通常加上前缀 m_
例如
m_number
m_server
m_port
m_buffer;
m_maxsize;
其中, m代表的是member这个单词,成员的意思

补充
如果没有访问修饰符,则默认是private的

4类的封装

类的封装
所谓封装,是指把细节隐藏在内部,只把函数接口暴露在外。
封装的是什么? 数据,逻辑。
在C/struct时代,由于struct内部是可以自由访问的,所以 无法完全地实现封装。(用户可能不小心破坏内部数据)
在引入class和访问修饰符后,就可以实现完全地封装。

类的封装
首先要明确:什么东西想让用户看到,什么东西不相让用户 看到。

  1. 把所有的成员变量设为private
  2. 添加函数接口,供外部操作该对象
    (getter/setter, 及其他功能接口)
    C/C++学习指南 邵发 www.afanihao.cn
    例1 圆
    直角坐标系中的一个圆Circle,有圆心坐标(x,y), 半径radius。
    class Circle
    {
    public:
    void MoveTo(int x, int)
    {
    }
    void SetRadius(int radius)
    {
    }
    private:
    int m_x;
    int m_y;
    int m_radius;
    };

例1 圆
成员变量:
完全公开,就用public
完全不允许访问,就用private
只读:getter: 该成员是可以读的
只写:setter: 该成员是可以写的

例2 DataStore
升级第19章的例子,用class实现
class DataStore
{
public:
void Create() {}
void Destroy(){}
void Add(const Student* data){}
void Print(){}
private:
Student m_head;
};

小结

  1. 用访问修饰 符可以实现类的封装
  2. 很明确告诉用户,哪些是可以调用,哪些不能调用的。
    public:
    private:
    C
5class的头文件与源文件分离

class的分离式写法
把class的成员函数的定义写在class之外,即class的大括号的 外面。
例如, /// main.cpp
class Object
{
public:
int x;
void Test(); // (1) 成员函数的声明
};
void Object::Test() //(2) 成员函数写在外边,加上类名限定
{
}

class的分离式写法
总结一下这种写法:
(1)成员变量:还是写在类里面
(2)成员函数:在类里保留其函数声明,而函数的定义写在 类体之外。
(3)写在外面的时候,要加上类名限定(Object:: ) 其中,::可以理解为是表示范围的符

分开为头文件和源文件
按照一贯的原则:类型定义写在头文件里,函数实现写在源 文件里。 /// Object.h
class Object
{
public:
int x;
void Test();
};

分开为头文件和源文件
/// Object.cpp
#include <stdio.h>
#include “Object.h”
void Object::Test()
{
printf(“x is %d \n”, x); // 仍然可以省略this->
}

分开为头文件和源文件
更多例子
class DataStore
{
public:
void Create() ;
void Destroy();
void Add(const Student* data);
void Print();
private:
Student m_head;
};

注意

  1. 不一定要把所有函数定义都拿出来,可以只拿一部分出 来。
    如果写在类体里面,编译器按照inline的规则编译它
    (inline在第8章定义) 类体之外,则是普通的函数
  2. 在类体中,成员函数与成员变量的排列顺序是自由的。

学习资源 《C语言/C++学习指南》语法篇(从入门到精通)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值