c++笔记

对象初始化

对象初始化指的是在创建一个对象后,为其属性或成员变量赋予初始值的过程。这个过程确保对象在使用前具有合理的初始状态。在C++中,对象初始化通常发生在构造函数调用时,构造函数用于初始化对象的成员变量。初始化与赋值不同,初始化是在对象创建时赋予其初始值,而赋值是在对象已经存在的情况下,改变其当前值。在对象初始化时,可以通过各种方式,如使用默认值、从其他对象复制值、通过参数传递值等方式来设置对象的初始状态。

成员函数

成员函数是C++等面向对象编程语言中的一个重要概念。它是定义在类内部的函数,可以通过类的对象来调用。

成员函数具有访问类内部成员(包括私有成员和保护成员)的权限,这是非成员函数所不具备的。

成员函数可以定义在类体内,也可以定义在类体外。如果定义在类体外,但在函数名前加上`inline`修饰符,那么它仍然被视为内联函数。内联函数在编译时会被替换到调用它的地方,而不是在运行时进行函数调用,这有助于减少函数调用的开销。

此外,成员函数具有重载性、隐藏性和可以设置默认参数等特点。这意味着同一个类中可以有多个同名但参数不同的成员函数,而且成员函数可以被声明为私有(private)、公有(public)或保护(protected),以控制其访问权限。

总之,成员函数是面向对象编程中不可或缺的一部分,它允许我们在类的内部定义操作,并通过类的对象来访问这些操作。

 

类的成员函数主要包括以下几种:

1. **构造函数**:

用于初始化对象。构造函数在定义一个对象时自动执行一次,函数名与类名相同,没有返回值,且不能重载。如果类定义中没有给出构造函数,C++编译器会自动生成一个缺省的构造函数。

2. **拷贝构造函数**:

用于创建一个对象作为另一个对象的副本。拷贝构造函数的参数是类对象本身的引用,通常用于对象的初始化。

3. **析构函数**:

用于释放对象所使用的资源。析构函数在对象生命周期结束时自动调用,用于执行清理任务,如释放内存。析构函数没有参数,不能重载,且每个类只能有一个析构函数。

4. **赋值操作符重载**:

用于实现对象之间的赋值操作。通过重载赋值操作符,可以自定义对象赋值的行为。

5. **取地址操作符重载**:

用于获取对象的地址。通过重载取地址操作符,可以自定义对象取地址的行为。

6. **const修饰的取地址操作符重载**:

用于获取对象的const地址。这个操作符返回的是指向const对象的指针,可以保证对象不会被修改。

以上六种成员函数是类默认生成的成员函数,但也可以根据需要自行定义和重载。在定义成员函数时,需要注意函数的参数、返回值、访问控制等特性,以确保函数的正确性和安全性。

友元函数不是类的成员函数的原因主要有以下几点:

1. **访问权限**:友元函数被设计为能够访问类的私有和保护成员,而不需要通过类的对象。这是友元函数的主要特点之一。如果友元函数是类的成员函数,那么它将通过类的对象来访问类的成员,这与友元函数的初衷相违背。
2. **定义方式**:友元函数可以在类的内部或外部定义,而类的成员函数必须在类的内部定义。这种定义方式的不同也体现了友元函数与成员函数的不同性质。
3. **调用方式**:友元函数可以通过类的对象直接调用,而不需要使用对象来调用。这与成员函数的调用方式是不同的,成员函数必须通过类的对象来调用。
4. **封装性**:类的成员函数是类的一部分,它们遵循类的封装原则。而友元函数不是类的一部分,它们不受类的封装原则的限制。这种差异使得友元函数在设计和使用时具有更大的灵活性。

总的来说,友元函数的设计初衷是为了提供一种能够访问类的私有和保护成员的机制,同时保持类的封装性。因此,友元函数不是类的成员函数,而是与类相关联的一种特殊函数。

 

在C++中,如果一个类没有显式地定义析构函数(destructor)

编译器会自动为它生成一个默认的析构函数。这个默认的析构函数通常是一个空函数,不执行任何操作。默认的析构函数函数体通常如下所示:

```cpp

class ClassName {

public:

    ~ClassName() {

        // 默认析构函数的函数体为空

    }

};

```

在这个例子中,`ClassName` 是一个类的名称,`~ClassName()` 是该类的析构函数。由于我们没有在函数体中定义任何操作,因此析构函数不会执行任何动作。

然而,如果你需要在析构函数中执行一些清理操作,比如释放动态分配的内存或关闭文件等,你就需要显式地定义析构函数。例如:

```cpp

class MyClass {

private:

    int* ptr;

 

public:

    MyClass() {

        ptr = new int; // 在构造函数中分配内存

    }

 

    ~MyClass() {

        delete ptr; // 在析构函数中释放内存

    }

};

```

在这个例子中,`MyClass` 的析构函数会释放由构造函数分配的内存。如果我们没有显式地定义析构函数,那么当 `MyClass` 的对象被销毁时,内存将不会被释放,这可能会导致内存泄漏。

创建类对象,自动调用构造函数

在C++中,当你创建一个类的对象时,构造函数会自动被调用。这是C++语言的一个基本特性。以下是一个简单的例子,演示了如何定义一个类以及它的构造函数,并通过创建对象来自动调用这个构造函数。

```cpp
#include <iostream>

// 定义一个名为MyClass的类
class MyClass {
public:
    // 构造函数,当创建MyClass的对象时会被自动调用
    MyClass() {
        // 构造函数的函数体
        std::cout << "MyClass constructor called." << std::endl;
        // 在这里可以执行初始化操作
    }

    // 其他成员函数和成员变量...
};

int main() {
    // 创建MyClass的一个对象
    MyClass myObject;

    // 此时,MyClass的构造函数会被自动调用
    // 输出:"MyClass constructor called."

    return 0;
}
```

在这个例子中,`MyClass` 是一个简单的类,它有一个默认的构造函数(没有参数)。当我们在 `main` 函数中创建 `MyClass` 的一个对象 `myObject` 时,`MyClass` 的构造函数就会被自动调用。

如果你想通过语句来自动调用其他类型的构造函数(比如复制构造函数或列表初始化构造函数),你也可以通过相应的操作来实现。例如,复制构造函数会在以下情况被调用:

- 当一个对象被另一个对象初始化时(即复制初始化)。
- 当一个对象以值传递的方式传入函数时。
- 当一个对象从函数以值返回时。

下面是一个复制构造函数的例子:

```cpp
class MyClass {
public:
    // 默认构造函数
    MyClass() {
        std::cout << "Default constructor called." << std::endl;
    }

    // 复制构造函数
    MyClass(const MyClass& other) {
        std::cout << "Copy constructor called." << std::endl;
        // 在这里可以执行复制操作
    }
};

int main() {
    MyClass firstObject;  //

运用数组,多次调用类的构造函数

在C++中,构造函数调用的次数取决于你如何定义和初始化对象。在你给出的代码片段 `Xa[3]` 和 `*p[2]` 中,构造函数的调用次数取决于 `X` 类的定义以及 `a` 和 `p` 的声明和初始化。

1. 对于 `Xa[3]`:

   - 如果 `X` 是一个类,并且 `a` 是一个 `X` 类型的数组,那么 `Xa[3]` 表示声明了一个包含3个 `X` 类型对象的数组。在这种情况下,构造函数会被调用3次,因为每个数组元素都是一个新的 `X` 对象,它们的构造函数在数组创建时会被自动调用。

   - 如果 `X` 是一个函数,那么 `Xa[3]` 是不合法的语法,因为函数名不能用于数组声明。

2. 对于 `*p[2]`:

   - 如果 `p` 是一个指向 `X` 类型对象的指针数组,即 `X* p[2]`,那么 `*p[2]` 表示解引用数组 `p` 的第三个元素(注意,数组的索引是从0开始的,所以 `p[2]` 是数组的第三个元素)。然而,这个表达式本身不会调用构造函数,因为 `p` 的元素只是指针,它们指向的对象可能在其他地方被创建和初始化。

   - 如果 `p` 是一个 `X` 类型的数组,即 `X p[2]`,那么 `*p[2]` 是不合法的语法,因为 `p[2]` 是一个 `X` 类型的对象,不能被解引用。

   - 如果 `p` 是一个 `X` 类型的指针,即 `X* p`,并且 `p` 被初始化为指向一个 `X` 类型的对象,那么 `*p` 会解引用这个指针,访问它所指向的对象。然而,这并不会调用构造函数,因为对象的创建和初始化发生在 `p` 被赋值的时候。

总结来说,`Xa[3]` 会在创建数组时调用 `X` 类的构造函数3次(如果 `X` 是一个类且 `a` 是一个 `X` 类型的数组)。而 `*p[2]` 本身不会调用构造函数,它取决于 `p` 的类型和初始化方式。如果 `p` 是一个指针数组,并且这些指针指向的对象在其他地方被创建和初始化,那么构造函数的调用次数将取决于这些对象的创建方式。如果 `p` 是一个普通数组或单个指针,那么 `*p[2]` 的语法可能是错误的,并且不会涉及构造函数的调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值