readme
class是c++的核心,是“封装继承多态(大家都懂LOL~)”的抓手。c++ primer很详细的介绍了相关知识,很详细很详细,就是。。。不好懂。
这篇博客根据个人的理解,用我自以为更容易理解的文字,总结c++中class相关知识,内附用于帮助理解的可以编译通过的例程,逐步更新。
测试程序
//common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#include <string>
#include <stdio.h>
#include <set>
#include <memory>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <utility>
#include <algorithm>
#include <map>
#include <numeric>
#include <vector>
#include <iterator>
#include <sys/time.h>
using namespace std;
#endif
//class_sum.h
#ifndef _CLASS_SUM_H
#define _CLASS_SUM_H
#include "common.h"
//为了友元相关依赖关系
class Base;
class ClassIni {
public:
ClassIni();
~ClassIni();
void ClassIniPublicFunc();
private:
int ClassIniPrivateInt1;
int ClassIniPrivateInt2;
Base *base;
};
class StaticClass {
public:
StaticClass();
~StaticClass();
void StaticClassPublicSetFunc(const int &&value);
static void StaticClassPublicPrintFunc(){
printf("in StaticClass::StaticClassPublicPrintFunc\n");
printf("StaticClassPrivateInt: %d\n", StaticClassPrivateInt);
};
//编译报错
//void StaticClassPublicFunc(int value = StaticClassNonStaticInt);
void StaticClassPublicFunc(int value = StaticClassPrivateInt);
private:
int StaticClassNonStaticInt;
static int StaticClassPrivateInt;
const static int StaticClassConstPrivateInt = 0;
};
class Base
{
public:
Base();
virtual ~Base();
void BasePublicFunc();
int BasePublicInt;
//友元函数
friend void FriendFuncOfBase(const Base&);
//友元类
friend class FriendClassOfBase;
//友元类的成员函数
friend void ClassIni::ClassIniPublicFunc();
private:
int BasePrivateInt;
void BasePrivateFunc();
protected:
int BaseProtectedInt;
void BaseProtectedFunc();
};
//Base类的友元函数
void FriendFuncOfBase(const Base&);
//Base类的public继承子类
class DerivePublic : public Base
{
public:
DerivePublic();
~DerivePublic();
void DerivePublicPublicFunc();
private:
int DerivePublicPrivateInt;
protected:
int DerivePublicProtectedInt;
};
//Base类的友元类
class FriendClassOfBase {
public:
FriendClassOfBase();
~FriendClassOfBase();
void FriendClassOfBasePublicFunc();
private:
Base base;
DerivePublic derivepublic;
};
//Base类的private继承子类
class DerivePrivate : private Base {
public:
DerivePrivate();
~DerivePrivate();
void DerivePrivatePublicFunc();
};
//Base类的protected继承子类
class DeriveProtected : private Base {
public:
DeriveProtected();
~DeriveProtected();
void DeriveProtectedPublicFunc();
};
#endif
//class_sum.cpp
#include "class_sum.h"
//编译有报警,初始化列表顺序要和声明顺序一致
//ClassIni::ClassIni() : ClassIniPrivateInt2(0), ClassIniPrivateInt1(ClassIniPrivateInt2){
ClassIni::ClassIni() : ClassIniPrivateInt1(ClassIniPrivateInt2), ClassIniPrivateInt2(0){
base = new Base();
}
ClassIni::~ClassIni(){
delete base;
}
void ClassIni::ClassIniPublicFunc(){
printf("in ClassIni::ClassIniPublicFunc\n");
printf("ClassIniPrivateInt1: %d, ClassIniPrivateInt2: %d\n", ClassIniPrivateInt1, ClassIniPrivateInt2);
printf("base->BasePublicInt: %d, base->BasePrivateInt: %d, base->BaseProtectedInt: %d\n",
base->BasePublicInt, base->BasePrivateInt, base->BaseProtectedInt);
}
//类中的static成员变量
StaticClass::StaticClass(){}
StaticClass::~StaticClass(){}
int StaticClass::StaticClassPrivateInt = 0;
void StaticClass::StaticClassPublicSetFunc(const int &&value){
printf("in StaticClass::StaticClassPublicSetFunc, origin StaticClassPrivateInt: %d, value: %d\n",
StaticClassPrivateInt, value);
StaticClassPrivateInt = value;
}
//Base,父类
Base::Base() : BasePublicInt(0), BasePrivateInt(0), BaseProtectedInt(0){}
Base::~Base(){}
void Base::BasePublicFunc(){
printf("in Base::BasePublicFunc\n");
printf("BasePublicInt: %d, BasePrivateInt: %d, BaseProtectedInt: %d\n", BasePublicInt,
BasePrivateInt, BaseProtectedInt);
BaseProtectedFunc();
BasePrivateFunc();
}
void Base::BasePrivateFunc(){
printf("in Base::BasePrivateFunc\n");
printf("BasePublicInt: %d, BasePrivateInt: %d, BaseProtectedInt: %d\n", BasePublicInt,
BasePrivateInt, BaseProtectedInt);
}
void Base::BaseProtectedFunc(){
printf("in Base::BaseProtectedFunc\n");
printf("BasePublicInt: %d, BasePrivateInt: %d, BaseProtectedInt: %d\n", BasePublicInt,
BasePrivateInt, BaseProtectedInt);
}
//DerivePublic,pulic继承的子类
DerivePublic::DerivePublic() : DerivePublicPrivateInt(0), DerivePublicProtectedInt(0){}
DerivePublic::~DerivePublic(){}
void DerivePublic::DerivePublicPublicFunc(){
printf("in DerivePublic::DerivePublicPublicFunc\n");
//public继承的子类成员函数可以直接访问父类的public和protected成员
printf("BasePublicInt: %d, BaseProtectedInt: %d\n", BasePublicInt, BaseProtectedInt);
BasePublicFunc();
BaseProtectedFunc();
//public继承的子类成员函数不能直接访问父类的private成员
//printf("BasePrivateInt: %d\n", c);
//BasePrivateFunc();
}
//DerivePrivate,private继承的子类
DerivePrivate::DerivePrivate(){}
DerivePrivate::~DerivePrivate(){}
void DerivePrivate::DerivePrivatePublicFunc(){
printf("in DerivePrivate::DerivePrivatePublicFunc\n");
//pivate继承的子类的成员函数可以直接访问父类的public和protected成员
printf("BasePublicInt: %d, BaseProtectedInt: %d\n", BasePublicInt, BaseProtectedInt);
BasePublicFunc();
BaseProtectedFunc();
//private继承的子类不能直接访问父类的private成员
//printf("BasePrivateInt: %d\n", BasePrivateInt);
//BasePrivateFunc();
}
//DeriveProtected,protected继承的子类
DeriveProtected::DeriveProtected(){}
DeriveProtected::~DeriveProtected(){}
void DeriveProtected::DeriveProtectedPublicFunc(){
printf("in DeriveProtected::DeriveProtectedPublicFunc\n");
//protected继承的子类的成员函数可以直接访问父类的public和protected成员
printf("BasePublicInt: %d, BaseProtectedInt: %d\n", BasePublicInt, BaseProtectedInt);
BasePublicFunc();
BaseProtectedFunc();
//protected继承的子类不能直接访问父类的private成员
//printf("BasePrivateInt: %d\n", BasePrivateInt);
//BasePrivateFunc();
}
//友元
void FriendFuncOfBase(const Base& base){
printf("in FriendFuncOfBase\n");
printf("base.BasePublicInt: %d, base.BasePrivateInt: %d, base.BaseProtectedInt: %d\n",
base.BasePublicInt, base.BasePrivateInt, base.BaseProtectedInt);
return;
}
FriendClassOfBase::FriendClassOfBase() : base(){}
FriendClassOfBase::~FriendClassOfBase(){}
void FriendClassOfBase::FriendClassOfBasePublicFunc(){
printf("in FriendClassOfBase::FriendClassOfBasePublicFunc\n");
printf("base.BasePublicInt: %d, base.BasePrivateInt: %d, base.BaseProtectedInt: %d\n",
base.BasePublicInt, base.BasePrivateInt, base.BaseProtectedInt);
//友元不能继承,FriendClassOfBase是Base的友元类,不能访问Base子类的private成员或protected成员
//printf("derivepublic.DerivePublicPrivateInt: %d, derivepublic.DerivePublicPrivateInt: %d\n",
// derivepublic.DerivePublicPrivateInt, derivepublic.DerivePublicProtectedInt);
//FriendClassOfBase是父类的友元类,可以访问子类中继承自父类的private成员和protected成员
printf("derivepublic.BasePrivateInt: %d, derivepublic.BasePortectedInt: %d\n",
derivepublic.BasePrivateInt, derivepublic.BaseProtectedInt);
return;
}
int main(void)
{
printf("################################################################################\n成员变量初始化:\n");
ClassIni classini;
classini.ClassIniPublicFunc();
printf("################################################################################\n类中的static成员:\n");
StaticClass staticclass1;
StaticClass staticclass2;
staticclass1.StaticClassPublicSetFunc(1);
staticclass2.StaticClassPublicPrintFunc();
printf("################################################################################\n访问控制(不包含继承):\n");
Base base;
printf("base.BasePublicInt: %d\n", base.BasePublicInt);
base.BasePublicFunc();
//Base类的private和protected成员,不能直接被Base类对象访问
//printf("base.BaseProtectedInt: %d\n", base.BaseProtectedInt);
//base.BaseProtectedFunc();
//printf("base.BasePrivateInt: %d", base.BasePrivateInt);
//base.BasePrivateFunc();
printf("################################################################################\n访问控制(public继承):\n");
DerivePublic derivepublic;
printf("derivepublic.BasePublicInt: %d\n", derivepublic.BasePublicInt);
derivepublic.DerivePublicPublicFunc();
derivepublic.BasePublicFunc();
//Base类的所有成员在public继承的子类中都维持原状,所以Base类的private和protected成员,不能直接被子类的对象访问
//printf("derivepublic.BaseProtectedInt: %d\n", derivepublic.BaseProtectedInt);
//derivepublic.BaseProtectedFunc();
//printf("derivepublic.BasePrivateInt: %d", derivepublic.BasePrivateInt);
//derivepublic.BasePrivateFunc();
printf("################################################################################\n访问控制(private继承):\n");
DerivePrivate deriveprivate;
deriveprivate.DerivePrivatePublicFunc();
//Base类的所有成员在private继承的子类中都是private,都不可被子类的对象直接访问
//deriveprivate.BasePublicFunc();
//printf("deriveprivate.BasePublicInt: %d\n", deriveprivate.BasePublicInt);
//printf("deriveprivate.BaseProtectedInt: %d\n", deriveprivate.BaseProtectedInt);
//deriveprivate.BaseProtectedFunc();
//printf("deriveprivate.BasePrivateInt: %d", deriveprivate.BasePrivateInt);
//deriveprivate.BasePrivateFunc();
printf("################################################################################\n访问控制(protected继承):\n");
DeriveProtected deriveprotected;
deriveprotected.DeriveProtectedPublicFunc();
//Base类的所有成员在protected继承的子类中都是protected,都不可被子类的对象直接访问
//deriveprotected.BasePublicFunc();
//printf("deriveprotected.BasePublicInt: %d\n", deriveprotected.BasePublicInt);
//printf("deriveprotected.BaseProtectedInt: %d\n", deriveprotected.BaseProtectedInt);
//deriveprotected.BaseProtectedFunc();
//printf("deriveprotected.BasePrivateInt: %d", deriveprotected.BasePrivateInt);
//deriveprotected.BasePrivateFunc();
printf("################################################################################\n友元:\n");
FriendFuncOfBase(base);
FriendClassOfBase friendclassofbase;
friendclassofbase.FriendClassOfBasePublicFunc();
classini.ClassIniPublicFunc();
return 0;
}
编译
g++ -o class_sum class_sum.cpp -O0 -g -Wall -std=c++11
执行
[root@***]# ./class_sum
################################################################################
成员变量初始化:
in ClassIni::ClassIniPublicFunc
ClassIniPrivateInt1: 32766, ClassIniPrivateInt2: 0
base->BasePublicInt: 0, base->BasePrivateInt: 0, base->BaseProtectedInt: 0
################################################################################
类中的static成员:
in StaticClass::StaticClassPublicSetFunc, origin StaticClassPrivateInt: 0, value: 1
in StaticClass::StaticClassPublicPrintFunc
StaticClassPrivateInt: 1
################################################################################
访问控制(不包含继承):
base.BasePublicInt: 0
in Base::BasePublicFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BasePrivateFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
################################################################################
访问控制(public继承):
derivepublic.BasePublicInt: 0
in DerivePublic::DerivePublicPublicFunc
BasePublicInt: 0, BaseProtectedInt: 0
in Base::BasePublicFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BasePrivateFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BasePublicFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BasePrivateFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
################################################################################
访问控制(private继承):
in DerivePrivate::DerivePrivatePublicFunc
BasePublicInt: 0, BaseProtectedInt: 0
in Base::BasePublicFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BasePrivateFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
################################################################################
访问控制(protected继承):
in DeriveProtected::DeriveProtectedPublicFunc
BasePublicInt: 0, BaseProtectedInt: 0
in Base::BasePublicFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BasePrivateFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
in Base::BaseProtectedFunc
BasePublicInt: 0, BasePrivateInt: 0, BaseProtectedInt: 0
################################################################################
友元:
in FriendFuncOfBase
base.BasePublicInt: 0, base.BasePrivateInt: 0, base.BaseProtectedInt: 0
in FriendClassOfBase::FriendClassOfBasePublicFunc
base.BasePublicInt: 0, base.BasePrivateInt: 0, base.BaseProtectedInt: 0
derivepublic.BasePrivateInt: 0, derivepublic.BasePortectedInt: 0
in ClassIni::ClassIniPublicFunc
ClassIniPrivateInt1: 32766, ClassIniPrivateInt2: 0
base->BasePublicInt: 0, base->BasePrivateInt: 0, base->BaseProtectedInt: 0
成员变量初始化
成员变量的初始化可以在初始化列表或构造函数中完成,但初始化列表中出现的顺序要和声明顺序一致,否则编译时会有报警。这个设计其实容易造成一些误解,很多人会觉得初始化列表中的先后顺序真会发挥什么作用似的。
事实上,成员变量初始化的顺序与他们在类定义中出现的顺序一致,初始化列表中的顺序并不会影响成员变量实际被初始化的顺序。在测试程序中,ClassIni类定义中,ClassIniPrivateInt1先出现,ClassIniPrivateInt2后出现,ClassIniPrivateInt1会先被初始化。假设程序写成被注释掉的那一行:
//cpp文件中
ClassIni::ClassIni() : ClassIniPrivateInt2(0), ClassIniPrivateInt1(ClassIniPrivateInt2){}
编译是会有报警,给人的感觉像是ClassIniPrivateInt2先被初始化成0,然后ClassIniPrivateInt1再被初始化成ClassIniPrivateInt2,其实不是这样。成员变量ClassIniPrivateInt1的初始化依赖ClassIniPrivateInt2,但ClassIniPrivateInt1先被初始化,ClassIniPrivateInt1初始化的时候ClassIniPrivateInt2的值还未确定,就埋下了一个隐患,打印出来的testPrivateInt2是一个未确定的值。
即便程序:
//cpp文件中
ClassIni::ClassIni() : ClassIniPrivateInt1(ClassIniPrivateInt2), ClassIniPrivateInt2(0){}
虽然编译不会有报警,但问题依然存在。由此可见初始化列表重的顺序不重要,成员变量初始化顺序取决于类定义中出现的顺序。
类中的static成员
类中的static成员不属于某一个特定的对象,而是被这个类所有的对象共享。与普通static变量一样,一旦static成员被定义,就将存活于整个程序生命周期。
static成员的声明,定义,初始化和使用都有特殊的规则。
- 声明的时候需要在语句前面加上static关键字。static成员可以是public,private或protected。
- static成员可以在内部或外部定义,例如测试程序中:
//cpp文件中
int StaticClass::StaticClassPrivateInt = 0;
//h文件中
static void StaticClass::StaticClassPublicPrintFunc(){
printf("in StaticClass::StaticClassPublicPrintFunc\n");
printf("StaticClassPrivateInt: %d\n", StaticClassPrivateInt);
};
一个static成员只能被定义一次,当在类的外部定义static成员时,不可重复使用static关键字。
- static成员变量可以在内部或外部初始化,但有一些特殊条件。如果某个static变量值可能随着程序运行会被修改,并且会在多个对象间共享,这种场景下如果在类的定义内部初始化,会导致这个static变量经常的被初始化,每次创建新的对象都会初始化,这不符合逻辑。所以对于non-const类型的static变量,不允许在类定义内部初始化。而const类型的static成员变量,既可以在类定义内部初始化,也可以在外部初始化。例如测试程序中:
//h文件中
const static int StaticClassConstPrivateInt = 0;
- 使用过程中,因为static成员不属于某个特定的对象,所以在static成员函数中不能使用this指针,但是可以使用对象来访问static成员。
有一些特定的场景只能使用static成员。
比如在下文中提到的ClassIni类中的Base类,如果Base类是static类型变量,那么可以直接在ClassIni类中添加一个Base类对象作为成员变量,因为static成员可以是不完整的,只要说明Base是个class,即便尚未经过定义,也可以将static类型的Base类对象作为ClassIni的成员变量。
再比如static成员变量可以用作类成员函数的默认参数,例如测试程序中:
//h文件中
//编译报错
//void StaticClassPublicFunc(int value = StaticClassNonStaticInt);
void StaticClassPublicFunc(int value = StaticClassPrivateInt);
究其原因,大致可以这样理解,static成员可以保证在成员函数被使用之前已经准备好,已经初始化好。但non-static成员无法保证这一点,所以有了这个特殊化规则。
访问控制
访问控制分两类,一类是类的对象是否可以访问,另一类是类的成员函数是否可以访问,这很容易混淆。
友元
如果希望其他函数,其他类或者其他类的成员访问类的非公有成员,方法是让它们成为类的友元。需要在类的定义中添加一条以friend开头的说明。
- 可以为类添加一个友元函数,这个函数可以想类的成员函数那样访问类的public,private和protected成员。例如程序中的FriendFuncOfBase函数。
- 可以为类添加一个友元类,这个友元类可以访问目标类的public,private和protected成员。例如FriendClassOfBase类。
- 可以为类添加一个其他类的成员函数作为友元函数,这个成员函数可以访问目标类的public,private和protected成员。这里需要注意目标类和其他类的声明定义依赖关系。例如ClassIni::ClassIniPublicFunc函数。
这里有一点提示,ClassIni类中的Base指针成员为什么必须是指针呢?因为在ClassIni类定义的时候,Base还是一个不完整的类型,如果直接定义成Base对象,编译会报错。
结合继承,还有一些额外的规则。
- 友元不可继承,父类的友元不可访问子类的private或protected成员。但父类的友元可以访问子类中继承自父类的private成员和protected成员。例如测试程序中:
//友元不能继承,FriendClassOfBase是Base的友元类,不能访问Base子类的private成员或protected成员
//printf("derivepublic.DerivePublicPrivateInt: %d, derivepublic.DerivePublicPrivateInt: %d\n",
// derivepublic.DerivePublicPrivateInt, derivepublic.DerivePublicProtectedInt);
//FriendClassOfBase是父类的友元类,可以访问子类中继承自父类的private成员和protected成员
printf("derivepublic.BasePrivateInt: %d, derivepublic.BasePortectedInt: %d\n",
derivepublic.BasePrivateInt, derivepublic.BaseProtectedInt);
- 依然是友元不可继承,友元类本身的父类或者子类,都不可访问目标类的private或protected成员。
访问控制(不包含继承)
public,protected和private是访问说明符,访问控制依据访问说明符。其中public之后声明定义的是公有成员,private之后声明定义的是私有成员,protected之后声明定义的是受保护成员,protected像是private和public的中合或结合。成员包括成员函数和成员变量。
- 类的对象可直接访问public成员。
- 类的对象不可直接访问private成员和protected成员,编译会报错。可通过类的成员函数访问private成员或protected成员。
- private成员函数可以访问protected成员,protected成员函数也可以访问private成员。
如果不包含继承,protected成员和private成员类似。
访问控制(包含继承)
结合到继承,复杂度有了些许的提高。父类对象或成员对父类成员的访问权限与上一节一致,不做重复讨论,只讨论子类对象或成员对父类成员的访问权限。
子类继承父类之后,子类对象或子类成员对父类某个成员的访问权限取决于两个因素:该成员的在父类中的访问说明符,继承列表中的访问说明符。
或者换一种思路,继承之后,父类的public和protected成员可以理解为成为了子类的成员,具体成为了哪种访问说明符的成员取决于它们在父类的访问说明符和继承列表中的访问说明符。而父类的private成员比较特殊,就像它的名字一样,它仅仅属于父类,是父类私有的,它不会在继承之后变成子类的成员,不管哪类继承,子类对象和子类成员函数都无法访问父类的private成员。对于父类的private成员,无论子类对象还是子类成员函数,都不能访问。只能通过子类成员函数调用父类public或protected成员函数,父类成员函数再访问父类的private成员这种间接的方式来实现。
下面是更详细的说明。
访问控制(public继承)
对于子类对象的访问权限,public继承中,父类的public成员变为子类的public成员,父类的protected成员变为子类的protected成员。
- 对于父类的public成员,子类对象和子类成员函数都可访问。
- 对于父类的protected成员,子类对象无法访问,子类成员函数可访问。
至此需要针对父类protected成员的访问权限整理一下。子类对象不可访问,这和父类private成员类似。子类的成员函数可访问,这和父类public成员相同。
访问控制(private继承)
对于子类对象的访问权限,private继承中,父类的public和protected成员都变为子类的private成员。
- 对于父类的public成员,子类对象无法访问,子类成员函数可访问。
- 对于父类的protected成员,子类对象无法访问,子类成员函数可访问
访问控制(protected继承)
对于子类对象的访问权限,protected继承中,父类的public和protected成员都变为子类的protected成员。
- 对于父类的public成员,子类对象无法访问,子类成员函数可访问。
- 对于父类的protected成员,子类对象无法访问,子类成员函数可访问。