C++ 类的简单介绍
类的定义、构造函数、析构函数、常量函数、仿函数、继承、多态、静态成员和类模板等
类和对象是C++的重要特性,也是其面向对象的基本,类的类容很多,本文只是简单介绍,包括类的定义、构造函数、析构函数、常量函数、仿函数、继承、多态、静态成员和类模板等
1. 类的定义
类是自定义的类型,基本形式如下所示,类的末尾有分号";"
class Master
{
public:
Master(); //构造函数
~Master(); //析构函数
//成员函数
public:
void addBloodVolume();
void reduceBloodVolume();
void showBloodVolume();
//在类的内部实现,默认是inline
void setBloodVolume(int32_t bloodVolume)
{
m_blood_volume = bloodVolume;
}
void addManaVolume();
void reduceManaVolume();
void showManaVolume();
//在类的内部实现,默认是inline
void setManaVolume(int32_t manaVolume)
{
m_mana_volume = manaVolume;
}
//成员变量
private:
int32_t m_blood_volume;
int32_t m_mana_volume;
};
2. 构造函数与析构函数
构造函数
构造函数决定了我们定义类对象的方式,默认是public,可以有多个
//第一种:
*.h文件
Master();
*.cc文件
Master::Master()
{
}
//第二种:
*.h文件
Master(){};
//第三种:
Master() = default; //编译器会自动生成默认的函数定义体
构造函数支持重载
Master() = default;
Master(int32_t bloodVolume, int32_t manaVolume);
//类对象的定义:
Master master;
//或
Master master(100, 90);
构造函数的初始化列表
Master(int32_t bloodVolume, int32_t manaVolume) : m_blood_volume(bloodVolume), m_mana_volume(manaVolume){ /* code */}; //构造函数
初始化 const 成员变量的一种方法就是使用初始化列表
//m_blood_volume如果为const,则该成员变量支持初始化列表赋值
const int32_t m_blood_volume;
析构函数
析构函数只能有1个,不能重载,一个类只能有一个析构函数,对象在销毁的时候自动调用;如果用户没有定义,则系统会自动生成
~Master();
空类,编译器一般会给类生成默认的6个函数;如果不使用的话,可以将其定义为private,并且在后面加delete
public:
Master(); //默认构造函数
~Master(); //默认析构函数
private:
Master(const Master &)=delete; //默认拷贝构造函数
Master(Master &&)=delete; //默认移动构造函数
Master &operator=(const Master &)=delete; //默认赋值函数
Master &operator=(Master &&)=delete; //默认移动赋值构造函数
3. public/private/protect
类的成员函数和成员变量有3种属性
class Games
{
//公有
public:
Games();
~Games();
//私有
private:
//保护
protected:
};
- 公有(public):在类内以及通过类的实例都可以访问
- 私有(private):在类内可以访问,类的实例不可以访问,子类不可以访问
- 保护(protect):在类内可以访问,类的实例不可以访问,子类可以访问
一般情况下,将对外的接口定义为public,其余定位为private,尤其是成员变量;protect根据使用情况而定;
4. 虚函数与纯虚函数
虚函数的关键字virtual;如果一个函数声明为虚函数,则允许基类的指针指向子类的该函数,该函数需要在子类中实现
基类
//声明
virtual void skill_q();
//实现
void Master::skill_q()
{
std::cout<<"skill q belong to master!"<<std::endl;
}
子类
class Karthus : public Master
{
public:
Karthus() = default;
~Karthus(){};
public:
void skill_q();
void skill_w();
void skill_e();
void skill_r();
};
实现
void Karthus::skill_q()
{
std::cout<<"skill q belong to karthus!"<<std::endl;
}
使用
int main(int argc, char *argv[])
{
Master *pmaster = new Master;
pmaster->skill_q();
delete pmaster;
Master *pmaster1 = new Karthus;
pmaster1->skill_q();
delete pmaster1;
return 0;
}
输出
skill q belong to master!
skill q belong to karthus!
纯虚函数
如果一个函数被声明为纯虚函数,则说明该类为抽象类,无法创建对象、也无法实例化(纯虚函数没有函数体,不是完整的函数)。抽象类通常是作为基类,让派生类去实现纯虚函数,抽象类通常作为对外接口,不暴露实现。
virtual void skill_w()=0; //该函数需要在子类中实现
5. 常量函数
在类的成员函数后面加上const,则该函数则被成为常量函数,常量函数的声明和实现都需要加上const;常量函数不允许修改成员变量,避免修改对象的内容,可以将函数定义为常量函数;
//声明
void addManaVolume() const;
//实现
void Master::addManaVolume() const
{
std::cout<<this->m_blood_volume<<std::endl;
}
常量函数不允许调用非常量函数;
常量函数可以调用常量函数;
void Master::addManaVolume() const
{
//showBloodVolume(); //不允许,常量函数不允许调用非常量函数
reduceManaVolume(); //允许,常量函数可以调用常量函数
std::cout<<this->m_blood_volume<<std::endl;
}
void Master::showBloodVolume()
{
std::cout<<"blood volume is: "<<m_blood_volume<<std::endl;
}
void Master::reduceManaVolume() const
{
std::cout<<"const test!"<<std::endl;
}
类的对象也可以声明为const,为常对象,常对象只能访问const成员变量和const成员函数;
const Karthus karthus;
6. 仿函数
仿函数就是仿造的函数,本质还是类,但是有了函数的特性,也叫做函数对象;仿函数需要重载operator()运算符;
举例说明仿函数的作用:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
class MyFunc
{
public:
bool operator()(int32_t x, int32_t y){return x > y;}
};
int main(int argc, char *argv[])
{
std::vector<int32_t> v = {12, 11, 3, 4, 5, 23};
MyFunc myfunc;
std::sort(v.begin(), v.end(), myfunc);
for(auto au : v)
{
std::cout<<au<<" ";
}
std::cout<<std::endl;
}
当然也可以通过lambda表达式来实现
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[])
{
std::vector<int32_t> v = {12, 11, 3, 4, 5, 23};
std::sort(v.begin(), v.end(), [](int32_t x,int32_t y){return x > y;});
for(auto au : v)
{
std::cout<<au<<" ";
}
std::cout<<std::endl;
}
7. 继承
继承允许一个类根据另外一个类来定义,继承可以实现代码的复用;
继承方式
class <派生类名> : <继承方式(public/protected/private)> <基类名>
- public:子类可以访问基类中的public和protected成员,其属性不变,不能访问private成员;
- protected:基类中的public和protect成员将成为子类中的protected成员;
- private:基类中的public和protect成员将成为子类中的private成员;
使用
class Master
{
public:
Master() = default;
//Master(); //默认构造函数
Master(int32_t bloodVolume, int32_t manaVolume) : m_blood_volume(bloodVolume), m_mana_volume(manaVolume){}; //构造函数
~Master(); //默认析构函数
private:
Master(const Master &)=delete; //默认拷贝构造函数
Master(Master &&)=delete; //默认移动构造函数
Master &operator=(const Master &)=delete; //默认赋值函数
Master &operator=(Master &&)=delete; //默认移动赋值构造函数
public:
virtual void skill_q();
virtual void skill_w();
void skill_e();
void skill_r();
void addBloodVolume();
void reduceBloodVolume();
//void showBloodVolume() = delete;
void showBloodVolume();
void setBloodVolume(int32_t bloodVolume)
{
//m_blood_volume = bloodVolume;
this->m_blood_volume = bloodVolume;
}
void addManaVolume() const;
void reduceManaVolume() const;
void showManaVolume();
void setManaVolume(int32_t manaVolume)
{
m_mana_volume = manaVolume;
}
public:
static int32_t m_count;
private:
int32_t m_blood_volume;
int32_t m_mana_volume;
};
class Karthus : public Master
{
public:
Karthus() = default;
~Karthus(){};
public:
void skill_q();
void skill_w();
void skill_e();
void skill_r();
};
一般情况下,继承方式会使用public;例如基类中的缓存队列,子类可以通过public的成员函数进行存储和获取;
8. 多态
什么是多态,多态就是让基类的指针可以访问子类的成员函数,基类中的方法需要定义为虚函数(virtual);
基类可以调用自身的方法,可以调用子类的方法,表现为多种形态,即为多态;
如果不使用多态的话,类Karthus、Syndra 和 Ryze都需要定义一遍,如果使用多态只需要将基类的指针指向子类即可;
头文件
#include <iostream>
#include <string>
class Master
{
public:
Master() = default;
Master(int32_t bloodVolume, int32_t manaVolume) : m_blood_volume(bloodVolume), m_mana_volume(manaVolume){}; //构造函数
~Master(); //默认析构函数
private:
Master(const Master &)=delete; //默认拷贝构造函数
Master(Master &&)=delete; //默认移动构造函数
Master &operator=(const Master &)=delete; //默认赋值函数
Master &operator=(Master &&)=delete; //默认移动赋值构造函数
public:
virtual void skill_q();
virtual void skill_w();
virtual void skill_e();
virtual void skill_r();
void addBloodVolume();
void reduceBloodVolume();
void showBloodVolume();
void setBloodVolume(int32_t bloodVolume)
{
this->m_blood_volume = bloodVolume;
}
void addManaVolume() const;
void reduceManaVolume() const;
void showManaVolume();
void setManaVolume(int32_t manaVolume)
{
m_mana_volume = manaVolume;
}
public:
static int32_t m_count;
private:
int32_t m_blood_volume;
int32_t m_mana_volume;
};
class Karthus : public Master
{
public:
Karthus() = default;
~Karthus(){};
public:
//以下函数在.cc中实现
void skill_q();
void skill_w();
void skill_e();
void skill_r();
};
class Syndra : public Master
{
public:
Syndra() = default;
~Syndra() {}
public:
void skill_q(){std::cout<<"skill q belong to Syndra!"<<std::endl;}
void skill_w(){std::cout<<"skill w belong to Syndra!"<<std::endl;}
void skill_e(){std::cout<<"skill e belong to Syndra!"<<std::endl;}
void skill_r(){std::cout<<"skill r belong to Syndra!"<<std::endl;}
};
class Ryze : public Master
{
public:
Ryze() = default;
~Ryze(){}
public:
void skill_q(){std::cout<<"skill q belong to Ryze!"<<std::endl;}
void skill_w(){std::cout<<"skill w belong to Ryze!"<<std::endl;}
void skill_e(){std::cout<<"skill e belong to Ryze!"<<std::endl;}
void skill_r(){std::cout<<"skill r belong to Ryze!"<<std::endl;}
};
main.cc
/* class test
* g++ -g class.h class.cc main.cc -o d -std=c++11
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "class.h"
int main(int argc, char *argv[])
{
Master *master = new Karthus;
master->skill_q();
master->skill_w();
master->skill_e();
master->skill_r();
std::cout<<std::endl;
master = new Syndra;
master->skill_q();
master->skill_w();
master->skill_e();
master->skill_r();
std::cout<<std::endl;
master = new Ryze;
master->skill_q();
master->skill_w();
master->skill_e();
master->skill_r();
std::cout<<std::endl;
return 0;
}
输出
skill q belong to karthus!
skill w belong to karthus!
skill e belong to karthus!
skill r belong to karthus!
skill q belong to Syndra!
skill w belong to Syndra!
skill e belong to Syndra!
skill r belong to Syndra!
skill q belong to Ryze!
skill w belong to Ryze!
skill e belong to Ryze!
skill r belong to Ryze!
9. void
void一般会翻译为无、空白等,这里主要介绍void作为参数的使用,void可以指向任何类型的地址
将多态main.cc的输出函数改一下
void show(void *ptr)
{
//Master *pMaster = (Master*)ptr;
Master *pMaster = reinterpret_cast<Master*>(ptr);
pMaster->skill_q();
pMaster->skill_w();
pMaster->skill_e();
pMaster->skill_r();
std::cout<<std::endl;
}
int main(int argc, char *argv[])
{
Master *master = new Karthus;
show(master);
master = new Syndra;
show(master);
master = new Ryze;
show(master);
return 0;
}
10. this指针
this是一个const指针,只能在类的内部使用,可以访问所有的成员变量和函数(public/private/protect)
void setBloodVolume(int32_t bloodVolume)
{
//m_blood_volume = bloodVolume;
this->m_blood_volume = bloodVolume;
}
11. 静态成员变量与静态成员函数
静态成员变量
静态成员变量在定义的时候需要加上static,是一种特殊的成员变量,无论该类创建多少个对象,静态成员变量只有1个,且共享
声明
class Karthus : public Master
{
public:
Karthus() = default;
~Karthus(){};
public:
void skill_q();
void skill_w();
void skill_e();
void skill_r();
void showCount()
{
std::cout<<"m_count value is: "<<m_count<<std::endl;
}
private:
static int32_t m_count;
};
初始化(必须在类外进行初始化),静态成员变量内存的分配是在初始化的时候,且分配一次;
//main.cc文件中
int32_t Karthus::m_count = 36;
使用(直接访问,通过对象或指针)
std::cout<<Karthus::m_count<<std::endl; //直接访问,当然m_count的属性需要为public
Karthus karthus;
karthus.showCount(); //通过对象访问
静态成员函数
静态成员函数在定义的时候需要加上static,其没有this指针,只能访问静态成员变量或静态成员函数
定义
class Karthus : public Master
{
public:
Karthus() = default;
~Karthus(){};
public:
void skill_q();
void skill_w();
void skill_e();
void skill_r();
static void skill_g();
static void skill_h();
void showCount()
{
std::cout<<"m_count value is: "<<m_count<<std::endl;
}
private:
static int32_t m_count;
};
void Karthus::skill_g()
{
m_count++;
std::cout<<"m_count(g) value is: "<<m_count<<std::endl;
}
void Karthus::skill_h()
{
//skill_e(); //不允许,会报错
skill_g();
m_count++;
std::cout<<"m_count(h) value is: "<<m_count<<std::endl;
}
使用
int main(int argc, char *argv[])
{
Karthus karthus;
karthus.showCount();
karthus.skill_g();
karthus.skill_h();
return 0;
}
输出
m_count value is: 36
m_count(g) value is: 37
m_count(g) value is: 38
m_count(h) value is: 39
12. 关键字override和final
override
override关键字,会让编译器检查是否正确覆写父类的虚函数;建议子类中需要覆写的虚函数加上override,这是个好习惯
实例
class Student
{
public:
Student() = default;
~Student(){}
public:
virtual void showInfo()
{
std::cout<<"the class is Student."<<std::endl;
}
};
class Girl : public Student
{
public:
Girl() = default;
~Girl(){}
public:
void showInfo()
{
std::cout<<"the class is Girl."<<std::endl;
}
};
int main(int argc, char *argv[])
{
Student *ptr = new Girl;
ptr->showInfo();
return 0;
}
输出
the class is Girl.
修改class Student的showInfo,修改内容如下所示
class Student
{
public:
Student() = default;
~Student(){}
public:
virtual void showInfo() const
{
std::cout<<"the class is Student."<<std::endl;
}
};
输出
the class is Student.
如果加上override,则会报错,提示没有覆写基类中的showInfo()
class Student
{
public:
Student() = default;
~Student(){}
public:
virtual void showInfo() const
{
std::cout<<"the class is Student."<<std::endl;
}
};
class Girl : public Student
{
public:
Girl() = default;
~Girl(){}
public:
void showInfo() override
{
std::cout<<"the class is Girl."<<std::endl;
}
};
final
final表示该类禁止被继承,该关键字在使用的时候需要特别注意;
以下代码无法编译通过,Student无法被继承
class Student final
{
public:
Student() = default;
~Student(){}
public:
virtual void showInfo()
{
std::cout<<"the class is Student."<<std::endl;
}
};
class Girl : public Student
{
public:
Girl() = default;
~Girl(){}
public:
void showInfo() override
{
std::cout<<"the class is Girl."<<std::endl;
}
};
13. 类模板
创建一个通用类,类中使用的类型可以先不指定;在创建类对象的时候再指定;
模板是泛型编程的基础,这里只是列举一下类模板的例子
template<class T1, class T2>
class Man
{
public:
void setValue(T1 name,T2 age)
{
m_nmae = name;
m_age = age;
}
void showInfo()
{
std::cout<<"name is: "<<m_nmae<<std::endl;
std::cout<<"age is: "<<m_age<<std::endl;
}
private:
T1 m_nmae;
T2 m_age;
};
int main(int argc, char *argv[])
{
Man<std::string, int32_t> man;
man.setValue("xiaoming",18);
man.showInfo();
Man<int32_t, int32_t> man1;
man1.setValue(01, 20);
man1.showInfo();
return 0;
}
输出
name is: xiaoming
age is: 18
name is: 1
age is: 20
class Person
{
public:
void show()
{
std::cout<<"person"<<std::endl;
}
};
template<class T>
class Boy
{
public:
void show()
{
t.show();
}
private:
T t;
};
int main(int argc, char *argv[])
{
Boy<Person> boy;
boy.show();
return 0;
}
输出
person
更多推荐


所有评论(0)