CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

C++类&对象详解

C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。

类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类被称为类的成员。

C++ 类定义

定义一个类,本质上是定义一个数据类型的蓝图。这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。

类定义是以关键字class开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。例如,我们使用关键字class定义 Box 数据类型,如下所示:

classBox{public:doublelength;// Length of a boxdoublebreadth;// Breadth of a boxdoubleheight;// Height of a box};

关键字public确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。您也可以指定类的成员为privateprotected,这个我们稍后会进行讲解。

定义 C++ 对象

类提供了对象的蓝图,所以基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。下面的语句声明了类 Box 的两个对象:

BoxBox1;// 声明 Box1,类型为 BoxBoxBox2;// 声明 Box2,类型为 Box

对象 Box1 和 Box2 都有它们各自的数据成员。

访问数据成员

类的对象的公共数据成员可以使用直接成员访问运算符 (.) 来访问。为了更好地理解这些概念,让我们尝试一下下面的实例:

includeusingnamespacestd;classBox{public:doublelength;// 长度doublebreadth;// 宽度doubleheight;// 高度};intmain(){BoxBox1;// 声明 Box1,类型为 BoxBoxBox2;// 声明 Box2,类型为 Boxdoublevolume=0.0;// 用于存储体积// box 1 详述Box1.height=5.0;Box1.length=6.0;Box1.breadth=7.0;// box 2 详述Box2.height=10.0;Box2.length=12.0;Box2.breadth=13.0;// box 1 的体积volume=Box1.height*Box1.length*Box1.breadth;cout<<"Box1 的体积:"<<volume<<endl;// box 2 的体积volume=Box2.height*Box2.length*Box2.breadth;cout<<"Box2 的体积:"<<volume<<endl;return0;}

当上面的代码被编译和执行时,它会产生下列结果:

Box1的体积:210Box2的体积:1560

需要注意的是,私有的成员和受保护的成员不能使用直接成员访问运算符 (.) 来直接访问。我们将在后续的教程中学习如何访问私有成员和受保护的成员。

类 & 对象详解

C++ 类成员函数

类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员。

让我们看看之前定义的类 Box,现在我们要使用成员函数来访问类的成员,而不是直接访问这些类的成员:

classBox{public:doublelength;// 长度doublebreadth;// 宽度doubleheight;// 高度doublegetVolume(void);// 返回体积};

成员函数可以定义在类定义内部,或者单独使用范围解析运算符 ::来定义。在类定义中定义的成员函数把函数声明为内联的,即便没有使用 inline 标识符。所以您可以按照如下方式定义getVolume()函数:

classBox{public:doublelength;// 长度doublebreadth;// 宽度doubleheight;// 高度doublegetVolume(void){returnlength*breadth*height;}};

您也可以在类的外部使用范围解析运算符 ::定义该函数,如下所示:

doubleBox::getVolume(void){returnlength*breadth*height;}

在这里,需要强调一点,在 :: 运算符之前必须使用类名。调用成员函数是在对象上使用点运算符(.),这样它就能操作与该对象相关的数据,如下所示:

Box myBox; // 创建一个对象

myBox.getVolume(); // 调用该对象的成员函数

让我们使用上面提到的概念来设置和获取类中不同的成员的值:

includeusingnamespacestd;classBox{public:doublelength;// 长度doublebreadth;// 宽度doubleheight;// 高度// 成员函数声明doublegetVolume(void);voidsetLength(doublelen);voidsetBreadth(doublebre);voidsetHeight(doublehei);};// 成员函数定义doubleBox::getVolume(void){returnlength*breadth*height;}voidBox::setLength(doublelen){length=len;}voidBox::setBreadth(doublebre){breadth=bre;}voidBox::setHeight(doublehei){height=hei;}// 程序的主函数intmain(){BoxBox1;// 声明 Box1,类型为 BoxBoxBox2;// 声明 Box2,类型为 Boxdoublevolume=0.0;// 用于存储体积// box 1 详述Box1.setLength(6.0);Box1.setBreadth(7.0);Box1.setHeight(5.0);// box 2 详述Box2.setLength(12.0);Box2.setBreadth(13.0);Box2.setHeight(10.0);// box 1 的体积volume=Box1.getVolume();cout<<"Box1 的体积:"<<volume<<endl;// box 2 的体积volume=Box2.getVolume();cout<<"Box2 的体积:"<<volume<<endl;return0;}

C++ 类访问修饰符

数据封装是面向对象编程的一个重要特点,它防止函数直接访问类类型的内部成员。类成员的访问限制是通过在类主体内部对各个区域标记public、private、protected来指定的。关键字public、private、protected称为访问修饰符。

一个类可以有多个 public、protected 或 private 标记区域。每个标记区域在下一个标记区域开始之前或者在遇到类主体结束右括号之前都是有效的。成员和类的默认访问修饰符是 private。

class Base {
 
   public:
 
  // 公有成员
 
   protected:
 
  // 受保护成员
 
   private:
 
  // 私有成员
 
};

公有(public)成员

公有成员在程序中类的外部是可访问的。您可以不使用任何成员函数来设置和获取公有变量的值,如下所示:

includeusingnamespacestd;classLine{public:doublelength;voidsetLength(doublelen);doublegetLength(void);};// 成员函数定义doubleLine::getLength(void){returnlength;}voidLine::setLength(doublelen){length=len;}// 程序的主函数intmain(){Lineline;// 设置长度line.setLength(6.0);cout<<"Length of line : "<<line.getLength()<<endl;// 不使用成员函数设置长度line.length=10.0;// OK: 因为 length 是公有的cout<<"Length of line : "<<line.length<<endl;return0;}

私有(private)成员

私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。

默认情况下,类的所有成员都是私有的。例如在下面的类中,width是一个私有成员,这意味着,如果您没有使用任何访问修饰符,类的成员将被假定为私有成员:

class Box
{
   double width;
   public:
      double length;
      void setWidth( double wid );
      double getWidth( void );
};

实际操作中,我们一般会在私有区域定义数据,在公有区域定义相关的函数,以便在类的外部也可以调用这些函数,如下所示:

includeusingnamespacestd;classBox{public:doublelength;voidsetWidth(doublewid);doublegetWidth(void);private:doublewidth;};// 成员函数定义doubleBox::getWidth(void){returnwidth;}voidBox::setWidth(doublewid){width=wid;}// 程序的主函数intmain(){Boxbox;// 不使用成员函数设置长度box.length=10.0;// OK: 因为 length 是公有的cout<<"Length of box : "<<box.length<<endl;// 不使用成员函数设置宽度// box.width = 10.0; // Error: 因为 width 是私有的box.setWidth(10.0);// 使用成员函数设置宽度cout<<"Width of box : "<<box.getWidth()<<endl;return0;}

protected(受保护)成员

protected(受保护)成员变量或函数与私有成员十分相似,但有一点不同,protected(受保护)成员在派生类(即子类)中是可访问的。

在下一个章节中,您将学习到派生类和继承的知识。现在您可以看到下面的实例中,我们从父类Box派生了一个子类smallBox

下面的实例与前面的实例类似,在这里width成员可被派生类 smallBox 的任何成员函数访问。

includeusingnamespacestd;classBox{protected:doublewidth;};classSmallBox:Box// SmallBox 是派生类{public:voidsetSmallWidth(doublewid);doublegetSmallWidth(void);};// 子类的成员函数doubleSmallBox::getSmallWidth(void){returnwidth;}voidSmallBox::setSmallWidth(doublewid){width=wid;}// 程序的主函数intmain(){SmallBoxbox;// 使用成员函数设置宽度box.setSmallWidth(5.0);cout<<"Width of box : "<<box.getSmallWidth()<<endl;return0;}

继承中的特点

有public, protected, private三种继承方式,它们相应地改变了基类成员的访问属性。

  • 1.public 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:public, protected, private
  • 2.protected 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:protected, protected, private
  • 3.private 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:private, private, private

但无论哪种继承方式,上面两点都没有改变:

  • 1.private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
  • 2.protected 成员可以被派生类访问。

public 继承

includeincludeusingnamespacestd;classA{public:inta;A(){a1=1;a2=2;a3=3;a=4;}voidfun(){cout<<a<<endl;//正确cout<<a1<<endl;//正确cout<<a2<<endl;//正确cout<<a3<<endl;//正确}public:inta1;protected:inta2;private:inta3;};classB:publicA{public:inta;B(inti){A();a=i;}voidfun(){cout<<a<<endl;//正确,public成员cout<<a1<<endl;//正确,基类的public成员,在派生类中仍是public成员。cout<<a2<<endl;//正确,基类的protected成员,在派生类中仍是protected可以被派生类访问。cout<<a3<<endl;//错误,基类的private成员不能被派生类访问。}};intmain(){Bb(10);cout<<b.a<<endl;cout<<b.a1<<endl;//正确cout<<b.a2<<endl;//错误,类外不能访问protected成员cout<<b.a3<<endl;//错误,类外不能访问private成员system("pause");return0;}

protected 继承

includeincludeusingnamespacestd;classA{public:inta;A(){a1=1;a2=2;a3=3;a=4;}voidfun(){cout<<a<<endl;//正确cout<<a1<<endl;//正确cout<<a2<<endl;//正确cout<<a3<<endl;//正确}public:inta1;protected:inta2;private:inta3;};classB:protectedA{public:inta;B(inti){A();a=i;}voidfun(){cout<<a<<endl;//正确,public成员。cout<<a1<<endl;//正确,基类的public成员,在派生类中变成了protected,可以被派生类访问。cout<<a2<<endl;//正确,基类的protected成员,在派生类中还是protected,可以被派生类访问。cout<<a3<<endl;//错误,基类的private成员不能被派生类访问。}};intmain(){Bb(10);cout<<b.a<<endl;//正确。public成员cout<<b.a1<<endl;//错误,protected成员不能在类外访问。cout<<b.a2<<endl;//错误,protected成员不能在类外访问。cout<<b.a3<<endl;//错误,private成员不能在类外访问。system("pause");return0;}

private 继承

includeincludeusingnamespacestd;classA{public:inta;A(){a1=1;a2=2;a3=3;a=4;}voidfun(){cout<<a<<endl;//正确cout<<a1<<endl;//正确cout<<a2<<endl;//正确cout<<a3<<endl;//正确}public:inta1;protected:inta2;private:inta3;};classB:privateA{public:inta;B(inti){A();a=i;}voidfun(){cout<<a<<endl;//正确,public成员。cout<<a1<<endl;//正确,基类public成员,在派生类中变成了private,可以被派生类访问。cout<<a2<<endl;//正确,基类的protected成员,在派生类中变成了private,可以被派生类访问。cout<<a3<<endl;//错误,基类的private成员不能被派生类访问。}};intmain(){Bb(10);cout<<b.a<<endl;//正确。public成员cout<<b.a1<<endl;//错误,private成员不能在类外访问。cout<<b.a2<<endl;//错误, private成员不能在类外访问。cout<<b.a3<<endl;//错误,private成员不能在类外访问。system("pause");return0;}

C++ 类构造函数 & 析构函数

类的构造函数

类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。

构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。

下面的实例有助于更好地理解构造函数的概念:

includeusingnamespacestd;classLine{public:voidsetLength(doublelen);doublegetLength(void);Line();// 这是构造函数private:doublelength;};// 成员函数定义,包括构造函数Line::Line(void){cout<<"Object is being created"<<endl;}voidLine::setLength(doublelen){length=len;}doubleLine::getLength(void){returnlength;}// 程序的主函数intmain(){Lineline;// 设置长度line.setLength(6.0);cout<<"Length of line : "<<line.getLength()<<endl;return0;}

使用初始化列表来初始化字段

使用初始化列表来初始化字段:

使用初始化列表来初始化字段:

Line::Line( double len): length(len) { cout << “Object is being created, length = ” << len << endl; }

上面的语法等同于如下语法:

Line::Line( double len) { length = len; cout << “Object is being created, length = ” << len << endl; }

假设有一个类 C,具有多个字段 X、Y、Z 等需要进行初始化,同理地,您可以使用上面的语法,只需要在不同的字段使用逗号进行分隔,如下所示:

C::C( double a, double b, double c): X(a), Y(b), Z(c) { …. }

类的析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

下面的实例有助于更好地理解析构函数的概念:

includeusingnamespacestd;classLine{public:voidsetLength(doublelen);doublegetLength(void);Line();// 这是构造函数声明~Line();// 这是析构函数声明private:doublelength;};// 成员函数定义,包括构造函数Line::Line(void){cout<<"Object is being created"<<endl;}Line::~Line(void){cout<<"Object is being deleted"<<endl;}voidLine::setLength(doublelen){length=len;}doubleLine::getLength(void){returnlength;}// 程序的主函数intmain(){Lineline;// 设置长度line.setLength(6.0);cout<<"Length of line : "<<line.getLength()<<endl;return0;}

C++ 拷贝构造函数

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。
  • 复制对象把它作为参数传递给函数。
  • 复制对象,并从函数返回这个对象。

如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下:

classname (const classname &obj) { // 构造函数的主体 }

在这里,obj是一个对象引用,该对象是用于初始化另一个对象的。

includeusingnamespacestd;classLine{public:intgetLength(void);Line(intlen);// 简单的构造函数Line(constLine&obj);// 拷贝构造函数~Line();// 析构函数private:int*ptr;};// 成员函数定义,包括构造函数Line::Line(intlen){cout<<"调用构造函数"<<endl;// 为指针分配内存ptr=newint;*ptr=len;}Line::Line(constLine&obj){cout<<"调用拷贝构造函数并为指针 ptr 分配内存"<<endl;ptr=newint;*ptr=*obj.ptr;// 拷贝值}Line::~Line(void){cout<<"释放内存"<<endl;deleteptr;}intLine::getLength(void){return*ptr;}voiddisplay(Lineobj){cout<<"line 大小 : "<<obj.getLength()<<endl;}// 程序的主函数intmain(){Lineline(10);display(line);return0;}

C++ 友元函数

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字friend,如下所示:

classBox{doublewidth;public:doublelength;friendvoidprintWidth(Boxbox);voidsetWidth(doublewid);};

声明类 ClassTwo 的所有成员函数作为类 ClassOne 的友元,需要在类 ClassOne 的定义中放置如下声明:

friend class ClassTwo;
includeusingnamespacestd;classBox{doublewidth;public:friendvoidprintWidth(Boxbox);voidsetWidth(doublewid);};// 成员函数定义voidBox::setWidth(doublewid){width=wid;}// 请注意:printWidth() 不是任何类的成员函数voidprintWidth(Boxbox){/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */cout<<"Width of box : "<<box.width<<endl;}// 程序的主函数intmain(){Boxbox;// 使用成员函数设置宽度box.setWidth(10.0);// 使用友元函数输出宽度printWidth(box);return0;}

C++ 内联函数

C++内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字inline,在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。

在类定义中的定义的函数都是内联函数,即使没有使用inline说明符。

下面是一个实例,使用内联函数来返回两个数中的最大值:

includeusingnamespacestd;inlineintMax(intx,inty){return(x>y)?x:y;}// 程序的主函数intmain(){cout<<"Max (20,10): "<<Max(20,10)<<endl;cout<<"Max (0,200): "<<Max(0,200)<<endl;cout<<"Max (100,1010): "<<Max(100,1010)<<endl;return0;}

C++ this 指针

在 C++ 中,每一个对象都能通过this指针来访问自己的地址。this指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。

友元函数没有this指针,因为友元不是类的成员。只有成员函数才有this指针。

下面的实例有助于更好地理解 this 指针的概念:

includeusingnamespacestd;classBox{public:// 构造函数定义Box(doublel=2.0,doubleb=2.0,doubleh=2.0){cout<<"Constructor called."<<endl;length=l;breadth=b;height=h;}doubleVolume(){returnlength*breadth*height;}intcompare(Boxbox){returnthis->Volume()>box.Volume();}private:doublelength;// Length of a boxdoublebreadth;// Breadth of a boxdoubleheight;// Height of a box};intmain(void){BoxBox1(3.3,1.2,1.5);// Declare box1BoxBox2(8.5,6.0,2.0);// Declare box2if(Box1.compare(Box2)){cout<<"Box2 is smaller than Box1"<<endl;}else{cout<<"Box2 is equal to or larger than Box1"<<endl;}return0;}

C++ 指向类的指针

一个指向 C++ 类的指针与指向结构体的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 ->,就像访问指向结构的指针一样。与所有的指针一样,您必须在使用指针之前,对指针进行初始化。

下面的实例有助于更好地理解指向类的指针的概念:

includeusingnamespacestd;classBox{public:// 构造函数定义Box(doublel=2.0,doubleb=2.0,doubleh=2.0){cout<<"Constructor called."<<endl;length=l;breadth=b;height=h;}doubleVolume(){returnlength*breadth*height;}private:doublelength;// Length of a boxdoublebreadth;// Breadth of a boxdoubleheight;// Height of a box};intmain(void){BoxBox1(3.3,1.2,1.5);// Declare box1BoxBox2(8.5,6.0,2.0);// Declare box2Box*ptrBox;// Declare pointer to a class.// 保存第一个对象的地址ptrBox=&Box1;// 现在尝试使用成员访问运算符来访问成员cout<<"Volume of Box1: "<<ptrBox->Volume()<<endl;// 保存第二个对象的地址ptrBox=&Box2;// 现在尝试使用成员访问运算符来访问成员cout<<"Volume of Box2: "<<ptrBox->Volume()<<endl;return0;}

C++ 类的静态成员

我们可以使用static关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。

静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符::来重新声明静态变量从而对它进行初始化,如下面的实例所示。

下面的实例有助于更好地理解静态成员数据的概念:

includeusingnamespacestd;classBox{public:staticintobjectCount;// 构造函数定义Box(doublel=2.0,doubleb=2.0,doubleh=2.0){cout<<"Constructor called."<<endl;length=l;breadth=b;height=h;// 每次创建对象时增加 1objectCount++;}doubleVolume(){returnlength*breadth*height;}private:doublelength;// 长度doublebreadth;// 宽度doubleheight;// 高度};// 初始化类 Box 的静态成员intBox::objectCount=0;intmain(void){BoxBox1(3.3,1.2,1.5);// 声明 box1BoxBox2(8.5,6.0,2.0);// 声明 box2// 输出对象的总数cout<<"Total objects: "<<Box::objectCount<<endl;return0;}

当上面的代码被编译和执行时,它会产生下列结果:

Constructor called.
Constructor called.
Total objects: 2

静态成员函数

如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符::就可以访问。

静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。

静态成员函数有一个类范围,他们不能访问类的 this 指针。您可以使用静态成员函数来判断类的某些对象是否已被创建。

静态成员函数与普通成员函数的区别:
  • 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
  • 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。
includeusingnamespacestd;classBox{public:staticintobjectCount;// 构造函数定义Box(doublel=2.0,doubleb=2.0,doubleh=2.0){cout<<"Constructor called."<<endl;length=l;breadth=b;height=h;// 每次创建对象时增加 1objectCount++;}doubleVolume(){returnlength*breadth*height;}staticintgetCount(){returnobjectCount;}private:doublelength;// 长度doublebreadth;// 宽度doubleheight;// 高度};// 初始化类 Box 的静态成员intBox::objectCount=0;intmain(void){// 在创建对象之前输出对象的总数cout<<"Inital Stage Count: "<<Box::getCount()<<endl;BoxBox1(3.3,1.2,1.5);// 声明 box1BoxBox2(8.5,6.0,2.0);// 声明 box2// 在创建对象之后输出对象的总数cout<<"Final Stage Count: "<<Box::getCount()<<endl;return0;}

当上面的代码被编译和执行时,它会产生下列结果:

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容