菜鸟教程 -- 学的不仅是技术,更是梦想!

C++ 教程
C++ 教程 C++ 简介 C++ 环境设置 C++ 基本语法 C++ 注释 C++ 数据类型 C++ 变量类型 C++ 变量作用域 C++ 常量 C++ 修饰符类型 C++ 存储类 C++ 运算符 C++ 循环 C++ 判断 C++ 函数 C++ 数字 C++ 数组 C++ 字符串 C++ 指针 C++ 引用 C++ 日期 & 时间 C++ 基本的输入输出 C++ 结构体(struct) C++ vector 容器 C++ 数据结构

C++ 面向对象

C++ 类 & 对象 C++ 继承 C++ 重载运算符和重载函数 C++ 多态 C++ 数据抽象 C++ 数据封装 C++ 接口(抽象类)

C++ 高级教程

C++ 文件和流 C++ 异常处理 C++ 动态内存 C++ 命名空间 C++ 模板 C++ 预处理器 C++ 信号处理 C++ 多线程 C++ Web 编程

C++ 资源库

C++ STL 教程 C++ 导入标准库 C++ 标准库 C++ 有用的资源 C++ 实例 C++ 测验 C++ <iostream> C++ <fstream> C++ <sstream> C++ <iomanip> C++ <array> C++ <vector> C++ <list> C++ <forward_list> C++ <deque> C++ <stack> C++ <queue> C++ <priority_queue> C++ <set> C++ <unordered_set> C++ <map> C++ <unordered_map> C++ <bitset> C++ <algorithm> C++ <iterator> C++ <functional> C++ <numeric> C++ <complex> C++ <valarray> C++ <cmath> C++ <string> C++ <regex> C++ <ctime> C++ <chrono> C++ <thread> C++ <mutex> C++ <condition_variable> C++ <future> C++ <atomic> C++ <type_traits> C++ <typeinfo> C++ <exception> C++ <stdexcept> C++ <cstdio> C++ <cstdint> C++ <memory> C++ <new> C++ <utility> C++ <random> C++ <locale> C++ <codecvt> C++ <cassert> C++ <cwchar> C++ <climits> C++ <cfloat> C++ <cstdlib> C++ <numbers> C++ OpenCV
(追記) (追記ここまで)

C++ 类 & 对象

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

类用于指定对象的形式,是一种用户自定义的数据类型,它是一种封装了数据和函数的组合。类中的数据称为成员变量,函数称为成员函数。类可以被看作是一种模板,可以用来创建具有相同属性和行为的多个对象。

C++ 类定义

定义一个类需要使用关键字 class,然后指定类的名称,并类的主体是包含在一对花括号中,主体包含类的成员变量和成员函数。

定义一个类,本质上是定义一个数据类型的蓝图,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。

以下实例我们使用关键字 class 定义 Box 数据类型,包含了三个成员变量 length、breadth 和 height:

classBox{public: doublelength; // 盒子的长度doublebreadth; // 盒子的宽度doubleheight; // 盒子的高度};

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

定义 C++ 对象

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

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

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

访问数据成员

类的对象的公共数据成员可以使用直接成员访问运算符 . 来访问。

为了更好地理解这些概念,让我们尝试一下下面的实例:

实例

#include<iostream>usingnamespacestd; classBox{public: doublelength; // 长度doublebreadth; // 宽度doubleheight; // 高度// 成员函数声明doubleget(void); voidset(doublelen, doublebre, doublehei); }; // 成员函数定义doubleBox::get(void){returnlength * breadth * height; }voidBox::set(doublelen, doublebre, doublehei){length = len; breadth = bre; height = hei; }intmain(){BoxBox1; // 声明 Box1,类型为 BoxBoxBox2; // 声明 Box2,类型为 BoxBoxBox3; // 声明 Box3,类型为 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; // box 3 详述Box3.set(16.0, 8.0, 12.0); volume = Box3.get(); cout << "Box3 的体积:" << volume <<endl; return0; }

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

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

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

类 & 对象详解

到目前为止,我们已经对 C++ 的类和对象有了基本的了解。下面的列表中还列出了其他一些 C++ 类和对象相关的概念,可以点击相应的链接进行学习。

概念描述
类成员函数 类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。
类访问修饰符 类成员可以被定义为 public、private 或 protected。默认情况下是定义为 private。
构造函数 & 析构函数 类的构造函数是一种特殊的函数,在创建一个新的对象时调用。类的析构函数也是一种特殊的函数,在删除所创建的对象时调用。
C++ 拷贝构造函数 拷贝构造函数,是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。
C++ 友元函数 友元函数可以访问类的 private 和 protected 成员。
C++ 内联函数 通过内联函数,编译器试图在调用函数的地方扩展函数体中的代码。
C++ 中的 this 指针 每个对象都有一个特殊的指针 this,它指向对象本身。
C++ 中指向类的指针 指向类的指针方式如同指向结构的指针。实际上,类可以看成是一个带有函数的结构。
C++ 类的静态成员 类的数据成员和函数成员都可以被声明为静态的。
AI 思考中...

7 篇笔记 写笔记

  1. #0

    董老爷

    zeh***[email protected]

    186

    关于C++中this指针的理解:当你进入一个房子后,你可以看到房子内的桌子、椅子、地板等;但是你看不到房子的全貌;对于类来说,你可以看到成员函数、成员变量,但你看不到实例本身,但是应用this可以让我们看到这个实例本身。

    我的理解:class类就好比这座房子,this就好比一把钥匙,通过钥匙来打开了这座房子的门,那么里面的东西就随意你取用了。

    因为this作用域是在类的内部,自己声明一个类的时候,还不知道实例化对象的名字,所以用this来使用对象变量的自身。在非静态成员函数中,编译器在编译的时候加上this作为隐含形参,通过this来访问各个成员(即使你没有写上this指针)

    代码实例:

    class Point
    { 
     int x, y;
     public:
     Point(int a, int b) { x=a; y=b;}
     void MovePoint( int a, int b){ x+=a; y+=b;}
     void print(){ cout<<"x="< }
     void main( )
     {
     Point point1( 10,10);
     point1.MovePoint(2,2);
     point1.print( );
     }
    }
    

    董老爷

    zeh***[email protected]

    9年前 (2017年11月05日)
  2. #0

    helloworld

    229***[email protected]

    385

    C++ 中的 struct 对 C 中的 struct 进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能。

    struct 能包含成员函数吗? 能!

    struct 能继承吗? 能!!

    struct 能实现多态吗? 能!!!

    既然这些它都能实现,那它和 class 还能有什么区别?

    最本质的一个区别就是默认的访问控制,体现在两个方面:

    1)默认的继承访问权限。struct是public的,class是private的。

    你可以写如下的代码:

    struct A
    {
     char a;
    };
    struct B : A
    {
     char b;
    };

    这个时候 B 是 public 继承 A 的。

    如果都将上面的 struct 改成 class,那么 B 是 private 继承 A 的。这就是默认的继承访问权限。

    所以我们在平时写类继承的时候,通常会这样写:

    struct B : public A

    就是为了指明是 public 继承,而不是用默认的 private 继承。

    当然,到底默认是 public 继承还是 private 继承,取决于子类而不是基类。

    我的意思是,struct 可以继承 class,同样 class 也可以继承 struct,那么默认的继承访问权限是看子类到底是用的 struct 还是 class。如下:

    struct A{}; 
    class B : A{}; //private继承
    struct C : B{}; //public继承

    2)struct 作为数据结构的实现体,它默认的数据访问控制是 public 的,而 class 作为对象的实现体,它默认的成员变量访问控制是 private 的。

    注意我上面的用词,我依旧强调 struct 是一种数据结构的实现体,虽然它是可以像 class 一样的用。我依旧将 struct 里的变量叫数据,class 内的变量叫成员,虽然它们并无区别。

    其实,到底是用 struct 还是 class,完全看个人的喜好,你可以将你程序里所有的 class 全部替换成 struct,它依旧可以很正常的运行。但我给出的最好建议,还是:当你觉得你要做的更像是一种数据结构的话,那么用 struct,如果你要做的更像是一种对象的话,那么用 class。

    当然,我在这里还要强调一点的就是,对于访问控制,应该在程序里明确的指出,而不是依靠默认,这是一个良好的习惯,也让你的代码更具可读性。

    说到这里,很多了解的人或许都认为这个话题可以结束了,因为他们知道 struct 和 class 的"唯一"区别就是访问控制。很多文献上也确实只提到这一个区别。

    但我上面却没有用"唯一",而是说的"最本质",那是因为,它们确实还有另一个区别,虽然那个区别我们平时可能很少涉及。那就是:"class" 这个关键字还用于定义模板参数,就像 "typename"。但关键字 "struct" 不用于定义模板参数。这一点在 Stanley B.Lippman 写的 Inside the C++ Object Model 有过说明。

    问题讨论到这里,基本上应该可以结束了。但有人曾说过,他还发现过其他的"区别",那么,让我们来看看,这到底是不是又一个区别。还是上面所说的,C++ 中的 struct 是对 C 中的 struct 的扩充,既然是扩充,那么它就要兼容过去 C 中 struct 应有的所有特性。例如你可以这样写:

    struct A //定义一个struct
    {
     char c1;
     int n2;
     double db3;
    };
    A a={'p',7,3.1415926}; //定义时直接赋值

    也就是说 struct 可以在定义的时候用 {} 赋初值。那么问题来了,class 行不行呢?将上面的 struct 改成 class,试试看。报错!噢~于是那人跳出来说,他又找到了一个区别。我们仔细看看,这真的又是一个区别吗?

    你试着向上面的 struct 中加入一个构造函数(或虚函数),你会发现什么?

    对,struct 也不能用 {} 赋初值了。

    的确,以 {} 的方式来赋初值,只是用一个初始化列表来对数据进行按顺序的初始化,如上面如果写成 A a={'p',7}; 则 c1,n2 被初始化,而 db3 没有。这样简单的 copy 操作,只能发生在简单的数据结构上,而不应该放在对象上。加入一个构造函数或是一个虚函数会使 struct 更体现出一种对象的特性,而使此{}操作不再有效。

    事实上,是因为加入这样的函数,使得类的内部结构发生了变化。而加入一个普通的成员函数呢?你会发现{}依旧可用。其实你可以将普通的函数理解成对数据结构的一种算法,这并不打破它数据结构的特性。

    那么,看到这里,我们发现即使是 struct 想用 {} 来赋初值,它也必须满足很多的约束条件,这些条件实际上就是让 struct 更体现出一种数据机构而不是类的特性。

    那为什么我们在上面仅仅将 struct 改成 class,{} 就不能用了呢?

    其实问题恰巧是我们之前所讲的——访问控制!你看看,我们忘记了什么?对,将 struct 改成 class 的时候,访问控制由 public 变为 private 了,那当然就不能用 {} 来赋初值了。加上一个 public,你会发现,class 也是能用 {} 的,和 struct 毫无区别!!!

    做个总结,从上面的区别,我们可以看出,struct 更适合看成是一个数据结构的实现体,class 更适合看成是一个对象的实现体。

    helloworld

    229***[email protected]

    9年前 (2018年01月16日)
  3. #0

    张家子谦

    492***[email protected]

    54

    在类的外面,其实也可以用指针访问类内部的私有成员,例如:

    #include <iostream>
    using namespace std;
    class a // 定义了类a
    {
     long a0; // 定义私有成员 a0
     public:
     a(long b)
     {
     a0=b;
     }
     void geta()
     {
     cout<<a0<<endl;
     }
    };
    int main()
    {
     a b(5); // 定义对象b,并给 b 中的 a0 赋初值
     long *p;
     p=(long*)&b; // 令指针 p 指向 b 中前 4 个字节,在这里相当于指向 a0
     b.geta(); // 用内部函数访问 a0
     cout<<*p<<endl; // 在外部直接访问 a0
     *p=8; // 在外部改变 a0 的值
     b.geta(); // 输出改变后的结果
     cout<<*p<<endl;
     return 0;
    }

    需要注意的是,使用这种方法虽然可以用于基于类的多态原则的一些程序开发,但违反了类的封装原则,在使用指针的类中也极不安全,所以不建议使用。

    张家子谦

    张家子谦

    492***[email protected]

    8年前 (2018年05月11日)
  4. #0
    621
    8年前 (2018年11月22日)
  5. #0

    csjpli

    ljp***@163.com

    44

    类对象初始化的时候加括号与不加括号有什么区别~

    #include<iostream>
    using namespace std;
     
    class A
    {
    public:
     A()
     {
     cout << "A()" << endl;
     }
     A(int a)
     {
     cout << "A(int a)" << endl;
     }
    };
     
    int main()
    {
     //栈上
     //warning C4930 : “A a(void)” : 未调用原型函数(是否是有意用变量定义的 ? )
     A a();//这里声明了一个函数,没有传入的参数,返回值为类类型
     cout << "~~~~~~~~~~~" << endl;
     A b;//默认调用“对象名()”这个构造函数构造对象
     cout << "~~~~~~~~~~~" << endl;
     A c(1);//默认调用相应的构造函数构造对象
     
     //堆上,加括号不加括号无差别,都调用默认的构造函数
     A *d = new A();
     A *e = new A;
     
     //对于内置类型而言,加括号是进行了初始化,不加是未进行初始化
     int *f = new int();
     int *g = new int;
     
     cout << *f << endl;
     cout << *g << endl;
     system("pause");
     return 0;
    }

    csjpli

    ljp***@163.com

    7年前 (2019年10月16日)
  6. #0

    修罗逮C

    dua***[email protected]

    11

    当把一个对象赋值给另一个对象时发生了什么?

    Box Box1; // 创建 Box1,执行后Box1已存在
    Box Box2; // 创建 Box2,执行后Box2已存在
    Box2 = Box1; // 这时是把Box1的成员变量值复制给了Box2,Box2还是原来的对象,并没有被销毁,对象地址还是原来的 地址。
    Box &Box3 = Box1; // 创建Box1的引用变量Box3. 

    其中 Box &Box3 = Box1,类似 Java 中 Box3 = Box1

    和 Java 中的区别:C++中的引用必须在创建时初始化,且创建后不能再指向别的对象,而 Java 中一个对象名可以随时指向另一个同类对象。

    用如下示例得出的以上论断:

    #include <iostream>
     
    using namespace std;
     
    class Box
    {
     public:
     double length; // 长度
     double breadth; // 宽度
     double height; // 高度
     // 成员函数声明
     double get(void);
     void set( double len, double bre, double hei );
    };
    // 成员函数定义
    double Box::get(void)
    {
     return length * breadth * height;
    }
     
    void Box::set( double len, double bre, double hei)
    {
     length = len;
     breadth = bre;
     height = hei;
    }
    int main( )
    {
     Box Box1; // 声明 Box1,类型为 Box
     Box Box2; // 声明 Box2,类型为 Box
     double volume = 0.0; // 用于存储体积
     
     // box 1 详述
     Box1.height = 5.0; 
     Box1.length = 6.0; 
     Box1.breadth = 7.0;
     
     
     // box 1 的体积
     volume = Box1.height * Box1.length * Box1.breadth;
     cout << "Box1 的地址:" << &Box1 <<endl;
     cout << "Box1 的体积:" << volume <<endl;
     
     // box 2 详述
     volume = Box2.get(); 
     cout << "Box2 的地址:" << &Box2 <<endl;
     cout << "Box2 的体积:" << volume <<endl;
     
     Box2 = Box1;
     volume = Box2.get();
     cout << "Box2 的地址:" << &Box2 <<endl;
     cout << "Box2 的体积:" << volume <<endl;
     return 0;
    }

    运行结果:

    Box1 的地址:0x7fff5b11a380
    Box1 的体积:210
    Box2 的地址:0x7fff5b11a360
    Box2 的体积:0
    Box2 的地址:0x7fff5b11a360
    Box2 的体积:210

    要深入理解这点请和拷贝构造函数和对象的引用放在一起对比理解。

    修罗逮C

    dua***[email protected]

    4年前 (2022年09月12日)
  7. #0

    侠客不留名

    405***[email protected]

    22

    这样理解比较直观,不然初学者根本理解不了。

    // 1. 基础准备
    #include <iostream> // 引入输入输出库
    using namespace std; // 使用标准命名空间(简化代码书写)
    // 2. 盒子类的声明
    class Box {
    public: // 公有访问权限(初学者先记住这是必要结构)
     // 成员变量(物体的三维属性)
     double length; // 长
     double breadth; // 宽
     double height; // 高
     
     // 成员函数声明(能力说明)
     double get(); // 获取体积
     void set(double l, double b, double h); // 设置尺寸
    };
    // 3. 成员函数具体实现
    double Box::get() { // 双冒号表示属于Box类的函数
     return length * breadth * height; // 体积计算公式
    }
    void Box::set(double l, double b, double h) {
     length = l; // 将参数值赋给成员变量
     breadth = b;
     height = h;
    }
    // 4. 主程序(使用案例)
    int main() {
     // 创建三个不同的盒子对象
     Box Box1, Box2, Box3; 
     double volume = 0; // 临时存储计算结果
     /* 操作方式对比 */
     // 方式一:直接操作成员变量(公开访问)
     Box1.height = 5; // ▢ 直接设置高度
     Box1.length = 6; // ▢ 直接设置长度
     Box1.breadth = 7; // ▢ 直接设置宽度
     volume = Box1.height * Box1.length * Box1.breadth;
     cout << "Box1体积:" << volume << endl; // 输出结果
     // 方式二:通过方法操作(推荐方式)
     Box3.set(16, 8, 12); // 一键设置所有尺寸
     volume = Box3.get(); // 自动计算体积
     cout << "Box3体积:" << volume << endl;
     return 0;
    }

    侠客不留名

    405***[email protected]

    1年前 (2025年04月07日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /