类与对象

定义一个类
class Box
{
public: //指定成员的访问权限,包括数据成员和方法成员
double length; // 类的数据成员,``类中的数据和方法称为类的成员
}; //需要有分号
定义对象Box box1;
访问数据成员 box1.length=5.0;只有public成员可以通过.进行访问,私有和受保护成员不可以
访问成员函数也是对象用**.**操作符,不能像普通函数一样直接调用

c++中,在类内部不能对数据成员直接赋值,比如class Box{ public:double length=0.0;};这是错的**

成员函数

成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义
在类定义中定义的成员函数也为内联函数。

class Box
{
public:
double getVolume(void)
{ return length * breadth * height; } };
此为成员函数

也可以定义在类外,使用范围解析运算符 :: 来定义 ,在函数名前加上 类名::即可
定义在类外时类内要声明函数

  1. class Box
  2. {
  3. public:
  4. double getVolume(void);// 声明函数
  5. };
  6. double Box::getVolume(void)
  7. {
  8. return length * breadth * height;
  9. }

c++中如果定义函数无参,最好写上带void,不要直接写(),应该(void),一种规范
**

内联函数

使用inline定义,比如inline int Max(int x, int y) { return (x > y)? x : y; }
内联函数一般与类一起使用(约等于成员函数,但是定义在类外
在类定义中定义的成员函数也为内联函数

数据隐藏

数据隐藏是防止直接访问类类型的内部成员。
通过在类主体内部对各个区域标记 public(公有)private(私有)protected** (受保护)这三个访问说明符实现
内联函数就是让编译器自动将内联函数内容(函数体)扩展到调用处。减少调用时间,以空间换时间;
当一个函数不太复杂,但是频繁调用。可以声明为内联函数**

成员和类的默认访问修饰符是 private。
一个类可以有多个 public、protected 或 private 标记区域。
class Base {
public:
// public members go here
protected:
// protected members go here
private:
// private members go here
};

  • 公有成员在程序中类的外部是可访问的。您可以不使用任何成员函数来设置和获取公有变量的值
  • 私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
  • 保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的

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

构造函数

类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
构造函数定义方法和成员函数一样,**只不过声明时不用写返回值,参数为void时声明不写void

构造函数带参数列表自然可以重载
class Line
{
public:
`** Line(); ** // 这是构造函数<br />};<br />Line::Line(void)<br />{<br /> cout << “Object is being created” << endl;<br />}<br />c++的构造函数不像java一样要通过new ?()调用,是**类创建新对象时自动调用**<br />**<br />**带参的构造方法**<br />类中声明:Line(double len);<br />定义Line::Line( double len) { cout << “Object is being created, length = “ << len << endl; length = len; }<br />主函数创建对象自动调用构造函数Line line(10.0);` 成员变量length就被赋予了10.0

使用初始化列表来初始化字段:
Line::Line( double len): length(len)
{ //这种形式:length(len)执行顺序是比cout...先执行
cout << "Object is being created, length = " << len << endl;
}
相当于上面的
Line::Line( double len) {
cout << "Object is being created, length = " << len << endl;
length = len; }

假设有一个类 C,具有多个数据成员X、Y、Z 等需要进行初始化,同理地,您可以使用上面的语法,只需要在不同的字段使用逗号进行分隔,如下所示:
C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
....
}

image.png

析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。(一般对象在离开其作用域时被删除,这里简单理解成程序执行完对象所在区域时被删除)

  • 析构函数的名称与类的名称是相似的,只是在前面加了个波浪号(~)作为前缀;

以上只是告诉你析构函数名称跟构造函数相似,但是不一样

  • 它不会返回任何值,也不能带有任何参数。(所以析构函数不能重载)(虽然可以看成是返回void,但是实际上连void都不应该有,不然内存还是释放不干净)

析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
析构函数用法上跟构造函数一样,就是名称前多了个~
Line(); // 这是构造函数声明 ~Line(); // 这是析构函数声明
Line::Line(void)
{
cout << "Object is being created" << endl;
}
Line::~Line()
{
cout << "Object is being deleted" << endl;
}

析构函数无形参,不可重载

拷贝构造函数

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

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

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

具体https://www.w3cschool.cn/cpp/cpp-copy-constructor.html

友元函数

友元函数是定义在类外部,**但有权访问类的所有私有(private)成员和保护(protected)成员。(自然也可以访问public成员)尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
这意味着友元函数可以像普通函数一样直接调用,但是却可以访问类的全部成员,但是又不需要借助对象就直接调用

友元函数以牺牲数据的封装性和隐蔽性,提高了程序的运行效率

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

语法
另外一个类B声明函数为Box的友元,需要在类定义中该函数原型前使用关键字 friend
class Box
{
double width;
public:
double length;
friendvoid B::printWidth( Box box ); 友元函数虽然定义在类外,但是类内要进行声明,但是类外定义是如同普通函数一样定义,而不是通过范围解析符::
void setWidth( double wid );
};

声明类 ClassTwo 的所有成员函数作为类 ClassOne 的友元在类 ClassOne 的定义时前加上friend关键字即可
friend class ClassTwo;//跟classone没关系

this指针

在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this** 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
友元函数没有
this 指针,因为友元不是类的成员。只有成员函数才有 this** 指针
用法为this->? ?为成员,this->?就相当于 调用this所在成员函数的对象.成员
this指针好处在于同样的代码可以使用不同对象的不同成员

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. public:
  6. // 构造函数定义,带有默认参数
  7. Box(double l=2.0, double b=2.0, double h=2.0)
  8. {
  9. cout <<"Constructor called." << endl;
  10. length = l;
  11. breadth = b;
  12. height = h;
  13. }
  14. double Volume() //返回体积
  15. {
  16. return length * breadth * height;
  17. }
  18. int compare(Box box) //定义比较体积的函数
  19. {
  20. //this调用传入compare的对象参数本身,并且让该对象调用成员函数Volume()
  21. return this->Volume() > box.Volume();
  22. }
  23. private:
  24. double length; // Length of a box
  25. double breadth; // Breadth of a box
  26. double height; // Height of a box
  27. };
  28. int main(void)
  29. {
  30. Box Box1(3.3, 1.2, 1.5); // Declare box1
  31. Box Box2(8.5, 6.0, 2.0); // Declare box2
  32. if(Box1.compare(Box2))
  33. {
  34. cout << "Box2 is smaller than Box1" <<endl;
  35. }
  36. else
  37. {
  38. cout << "Box2 is equal to or larger than Box1" <<endl;
  39. }
  40. return 0;
  41. }
  42. 当上面的代码被编译和执行时,它会产生下列结果:
  43. Constructor called.
  44. Constructor called.
  45. Box2 is equal to or larger than Box1

int compare(Box box) //定义比较体积的函数
{
//this调用传入compare的对象参数本身,并且让该对象调用成员函数Volume()
return this->Volume() > box.Volume();
}

if(Box1.compare(Box2))
最重要的就这两部代码第一步是比较函数,第二部是调用比较函数
return this->Volume() > box.Volume();
转为return 调用比较函数的对象->Volume() > 参数对象.Volume();
再转为return Box1->Volume() > Box2.Volume();
最后为return Box1.Volume() > Box2.Volume();

静态成员

static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能在类的定义中初始化静态成员,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化
类内要声明下静态成员static 数据类型 静态成员名; static和类型修饰符无先后之分,都是前缀

静态数据成员的数据类型 类::静态成员名=?;
以上指的是静态数据成员
无论是静态数据成员还是静态函数成员,都可以不借助对象直接通过类调用(但是也可以借助对象进行调用)

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. public:
  6. static int objectCount;
  7. // 构造函数定义
  8. Box(double l=2.0, double b=2.0, double h=2.0)
  9. {
  10. cout <<"Constructor called." << endl;
  11. length = l;
  12. breadth = b;
  13. height = h;
  14. // 每次创建对象时增加 1
  15. objectCount++;
  16. }
  17. double Volume()
  18. {
  19. return length * breadth * height;
  20. }
  21. private:
  22. double length; // 长度
  23. double breadth; // 宽度
  24. double height; // 高度
  25. };
  26. // 初始化类 Box 的静态成员
  27. int Box::objectCount = 0;
  28. int main(void)
  29. {
  30. Box Box1(3.3, 1.2, 1.5); // 声明 box1
  31. Box Box2(8.5, 6.0, 2.0); // 声明 box2
  32. // 输出对象的总数
  33. cout << "Total objects: " << Box::objectCount << endl;
  34. return 0;
  35. }
  36. 当上面的代码被编译和执行时,它会产生下列结果:
  37. Constructor called.
  38. Constructor called.
  39. Total objects: 2

静态函数成员

静态函数成员比静态数据成员要简单的多,直接在类内定义函数,函数加上前缀static即可。调用时还是通过
类::静态函数调用

指向类的指针(称作指向对象的指针会更贴切)

一个指向 C++ 类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 ->(有的地方又叫指向运算符)。
.是成员运算符
与所有的指针一样,您必须在使用指针之前,对指针进行初始化。

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. public:
  6. // 构造函数定义
  7. Box(double l=2.0, double b=2.0, double h=2.0)
  8. {
  9. cout <<"Constructor called." << endl;
  10. length = l;
  11. breadth = b;
  12. height = h;
  13. }
  14. double Volume()
  15. {
  16. return length * breadth * height;
  17. }
  18. private:
  19. double length; // Length of a box
  20. double breadth; // Breadth of a box
  21. double height; // Height of a box
  22. };
  23. int main(void)
  24. {
  25. Box Box1(3.3, 1.2, 1.5); // Declare box1
  26. Box Box2(8.5, 6.0, 2.0); // Declare box2
  27. Box *ptrBox; // Declare pointer to a class.
  28. //声明指向Box类类型的指针
  29. // 保存第一个对象的地址
  30. ptrBox = &Box1;
  31. // 现在尝试使用成员访问运算符来访问成员
  32. cout << "Volume of Box1: " << ptrBox->Volume() << endl;
  33. //相当于Box1.Volume()
  34. // 保存第二个对象的地址
  35. ptrBox = &Box2;
  36. // 现在尝试使用成员访问运算符来访问成员
  37. cout << "Volume of Box2: " << ptrBox->Volume() << endl;
  38. return 0;
  39. }
  40. 当上面的代码被编译和执行时,它会产生下列结果:
  41. Constructor called.
  42. Constructor called.
  43. Volume of Box1: 5.94
  44. Volume of Box2: 102

类类型的指针初始化为某个对象,使用 指针->?即相当于该指针对象调用?成员