一、目录
1、封装
2、对象初始化和清理
3、对象模型与this指针
4、友元
5、运算符重载
6、继承
二、封装
与C语言的面向过程思想不同,
在C++编程中,我们将万事万物看成对象,并把具有相同性质的对象抽象成类。
我们将属性和行为作为一个整体,用这些整体来表现生活中的事物。同时,我们可以将属性和行为加以权限控制。
重点:
1、访问权限:
1、公共权限 public 类内可以访问 类外可以访问
2、保护权限 protected 类内可以访问 类外不可以访问 儿子也可以访问父亲中的保护内容
3、私有权限 private 类内可以访问 类外不可以访问 儿子不可以访问父亲中的私有内容
举例:人类
class Person
{
//姓名 公共权限
public:
string m_Name;
//汽车 保护权限
protected:
string m_Car;
//银行卡密码 私有权限
private:
int m_Password;
public:
void func()
{
m_Name = "张三";
m_Car = "拖拉机";
m_Password = 123456;
}
};
三、对象初始化和清理
重点:
1、对象初始化和清理涉及安全问题。
2、通过构造函数和析构函数解决上述问题。
3、构造函数:
主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
构造函数语法:类名(){}
- 构造函数,没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
4、析构函数
主要作用在于对象销毁前系统自动调用,执行一些清理工作。
析构函数语法: ~类名(){}
- 析构函数,没有返回值也不写void
- 函数名称与类名相同,在名称前加上符号 ~
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
5、构造函数共有三种:
无参构造,有参构造,拷贝构造。
默认情况,C++编译器至少给一个类添加三个函数:
无参构造,拷贝构造,析构函数。
如果我们自主实现了有参构造,C++不再提供无参构造;
如果我们自主实现了拷贝构造,C++不再提供任何构造。
class Person
{
public:
int m_age;
public:
Person()
{
}
Person(int age)
{
m_age = age;
}
Person(const Person& p)
{
m_age = p.m_age;
}
};
【注】 拷贝构造传参传进的是引用,并且我们为了保证被拷贝的对象的数据安全,这里使用const关键字。
6、静态成员
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
class Person
{
public:
int m_age;
static int tall;
public:
Person()
{
}
Person(int age)
{
m_age = age;
}
Person(const Person& p)
{
m_age = p.m_age;
}
static void func()
{
cout << "static func!" << endl;
}
};
int Person::tall = 10;
int main()
{
Person p1;
p1.m_age = 1;
Person p2;
p2 = p1;
cout << p2.m_age<<endl;
cout << p1.tall;
p1.tall = 20;
cout << p2.tall;
Person::func();
p1.func();
return 0;
}
四、对象模型与this指针
重点:
1、C++对象模型中,空对象占用1个字节的内存空间。
2、只有非静态成员变量属于对象空间。
3、this指针是一个指针常量,它指向被调用的成员函数所属对象。
4、this指针可以用来区分同名的形参与成员变量。
5、在类的非静态成员函数中返回对象本身,可使用return *this
Person PersonAddPerson(Person p)
{
this->age += p.age;
//返回对象本身
return *this;
}
比如这里,我们执行下面代码:
Person p1;
p1.m_age = 1;
Person p2;
p2 = p1;
p1.PersonAddPerson(p2);
cout << p1.m_age;
得到的结果是2。
虽然这里是传值函数,
但是由于this始终指向的是调用这个函数的对象,也就是p1,
所以只要是对this->的成员变量进行修改,
都会作用在原对象上。
6、const修饰成员函数和对象后称之为常函数和常对象。常函数内不可修改成员属性,但如果在成员属性声明时加关键字mutable后,在常函数中依然可以修改。
class Person {
public:
Person() {
m_A = 0;
m_B = 0;
}
//this指针的本质是一个指针常量,指针的指向不可修改
//如果想让指针指向的值也不可以修改,需要声明常函数
void ShowPerson() const {
//const Type* const pointer;
//this = NULL; //不能修改指针的指向 Person* const this;
//this->mA = 100; //但是this指针指向的对象的数据是可以修改的
//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
this->m_B = 100;
}
//在成员函数后面加const,修饰的是this指向,相当于:const Person* const this;
//让指针指向的值也不可以修改。
void MyFunc() const {
//mA = 10000;
}
public:
int m_A;
mutable int m_B; //可修改 可变的
};
//const修饰对象 常对象
void test01() {
const Person person; //常量对象
cout << person.m_A << endl;
//person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
person.m_B = 100; //但是常对象可以修改mutable修饰成员变量
//常对象访问成员函数
person.MyFunc(); //常对象只能调用const的函数
}
int main() {
test01();
system("pause");
return 0;
}
五、友元
1、全局函数和类均可做友元,
声明方式为:
在类的大括号下第一行写上全局函数和类,
并在最前方加上friend关键字。
如:
全局函数:
friend void goodGay(Building * building);
类:
friend class goodGay;
别的类中的成员函数:
friend void goodGay::visit();
成为某个类中的友元后,即可访问其私有属性的成员或函数。
六、运算符重载
1、使用operator关键字进行重载。
2、<<运算符是ostream类的一个对象,且只能有一个。
重写输出函数举例:
ostream& operator<<(ostream& out, Person& p) {
out << "a:" << p.m_A << " b:" << p.m_B;
return out;
}
3、写自增运算符时,需要考虑两种情况并都实现,
如果只实现一种,会报错。
第二种由于不满足重载条件,可以使用占位参数。
Person& operator++()
{
this->m_age++;
return *this;
}
Person& operator++(int)
{
Person temp = *this;
this->m_age++;
return temp;
}
七、继承
1、继承方式一共有三种:
- 公共继承
- 保护继承
- 私有继承

2、从父类继承过来的私有成员虽然访问不到,但只是被隐藏了,还是会继承下去。
可以利用工具查看:
打开工具窗口后,定位到当前CPP文件的盘符
然后输入: cl /d1 reportSingleClassLayout查看的类名 所属文件名
3、继承中,先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
4、访问父类同名成员 需要加作用域
class Base {
public:
Base()
{
m_A = 100;
}
void func()
{
cout << "Base - func()调用" << endl;
}
void func(int a)
{
cout << "Base - func(int a)调用" << endl;
}
public:
int m_A;
};
class Son : public Base {
public:
Son()
{
m_A = 200;
}
//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
void func()
{
cout << "Son - func()调用" << endl;
}
public:
int m_A;
};
void test01()
{
Son s;
cout << "Son下的m_A = " << s.m_A << endl;
cout << "Base下的m_A = " << s.Base::m_A << endl;
s.func();
s.Base::func();
s.Base::func(10);
}
int main() {
test01();
system("pause");
return EXIT_SUCCESS;
}
5、利用虚继承解决菱形继承问题
class Animal
{
public:
int m_Age;
};
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep : virtual public Animal {};
class Tuo : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 100;
st.Tuo::m_Age = 200;
cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
cout << "st.m_Age = " << st.m_Age << endl;
}
int main() {
test01();
system("pause");
return 0;
}
这里运行结果:

本文详细介绍了C++编程中的封装概念,对象初始化和清理(包括构造函数、析构函数及静态成员)、this指针的使用、对象模型、运算符重载和继承机制,以及友元和常用操作符的重写技巧。
3238

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



