C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++类和对象之相关特性

C++类和对象之相关特性解读

作者:zzh_zao

这篇文章主要介绍了C++类和对象之相关特性,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一.类型转换

在C++中,类类型转换是指将一个类的对象转换为另一个类的对象,或者将一个类的对象转换为基本数据类型等。

C++提供了多种类型的转换机制,包括隐式类型转换和显式类型转换。

以下是关于C++类类型转换的详细介绍:

隐式类型转换

​构造函数实现的隐式转换

如果一个类的构造函数只有一个参数(除了可能的默认参数外),那么这个构造函数可以被用作隐式类型转换。例如:

class B {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->
public:
    B(int x) {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> /* ... */ }
};

这时,可以将int类型的值隐式转换为B类型的对象:

B b = 5; // 通过B的构造函数将5隐式转换为B对象

在类类型有多个参数时,可以使用{ xxx ,xxx },的形式来进行转换,不能使用(),因为()会计算出括号内最后一个表达式的值

类型转换运算符实现的隐式转换

类可以定义类型转换运算符,将类的对象隐式转换为其他类型。例如:

class A {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->
public:
    operator int() const {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> return 10; }
};

这时,A类型的对象可以隐式转换为int类型:

A a;
int x = a; // 通过A的类型转换运算符将a隐式转换为int

这种隐式转换可能会导致一些意外的错误,因此可以通过在构造函数前加上explicit关键字来禁止这种隐式转换:

class B {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->
public:
    explicit B(int x) {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> /* ... */ }
};

这样,B b = 5;就会报错,而必须显式地调用构造函数:B b(5);。

类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持

二.static成员

在C++中,static成员是类的一个重要特性,它与类本身相关联,而不是与类的某个具体对象相关联。这意味着static成员在类的所有对象之间是共享的。以下是对static成员的详细介绍:

static成员变量

定义与初始化

static成员变量是类的所有对象共享的变量。它在类的定义中声明,但需要在类的定义外进行初始化。 ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。例如:

class MyClass {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->
public:
    static int count; // 声明static成员变量
};

int MyClass::count = 0; // 初始化static成员变量

注意,static成员变量的初始化必须在类的定义外进行,且只能初始化一次。

访问方式

static成员变量可以通过类名或类的对象来访问,但推荐使用类名访问,以体现其与类的关系。例如:

MyClass::count = 10; // 通过类名访问
MyClass obj;
obj.count = 20; // 通过对象访问(不推荐,但合法)

无论通过类名还是对象访问,static成员变量都是同一个变量。

生命周期

static成员变量的生命周期从程序开始运行时初始化,到程序结束时销毁。它不依赖于类的对象的生命周期。

静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不⾛构造函数初始化列表.

static成员函数

定义与调用

static成员函数是与类相关联的函数,而不是与类的某个具体对象相关联。它不能访问非static成员变量和非static成员函数,因为这些成员需要对象的上下文。例如:

class MyClass {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->
public:
    static void print() {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->
        std::cout &lt;&lt; "Static function" &lt;&lt; std::endl;
    }
};
点击并拖拽以移动

static成员函数可以通过类名或类的对象来调用,但推荐使用类名调用。例如:

MyClass::print(); // 通过类名调用
MyClass obj;
obj.print(); // 通过对象调用(不推荐,但合法)

特点

应用场景

class MyClass {
public:
    static void incrementCount() { count++; }
    static int getCount() { return count; }
private:
    static int count;
};

int MyClass::count = 0;

int main() {
    MyClass::incrementCount();
    std::cout << MyClass::getCount() << std::endl; // 输出1
    return 0;
}

static成员的存储位置

心得:

三.友元

在C++中,友元(Friend) 是一个非常重要的概念,它允许某些特定的函数或类访问另一个类的私有(private)和保护(protected)成员。

这在某些情况下非常有用,尤其是当你需要在类的封装性与功能需求之间找到平衡时。

友元函数

定义

特点

友元类

定义

class MyClass {
private:
    int privateData;

public:
    MyClass(int data) : privateData(data) {}
    friend class FriendClass; // 声明友元类
};

class FriendClass {
public:
    void printPrivateData(const MyClass& obj) {
        std::cout << "Private Data: " << obj.privateData << std::endl;
    }
};

在这个例子中,FriendClassMyClass的友元类,因此FriendClass的所有成员函数都可以访问MyClass的私有成员privateData

特点

友元成员函数

定义

特点

小结:

四.内部类

如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

内部类默认是外部类的友元类。

内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地⽅都⽤不了。

内部类和外部类为平行关系,计算大小时不算内部类,内部类不算外部类的一部分,收访问限定符的限制

五.匿名对象

通常情况下,我们定义的是有名对象。

在C++中,匿名对象是指没有显式命名的对象。它们通常在需要临时使用某个类的对象时被创建,使用完毕后立即销毁。

匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可。

六.new

当使用动态内存分配(new)创建数组时,构造函数的调用机制与静态数组是相同的,但有一些额外的注意事项。

动态数组的构造函数调用
Sum* arr = new Sum[n];  // 动态创建长度为n的Sum数组

这行代码会:

  1. 在堆上分配足够存储n个Sum对象的内存
  2. 逐个调用每个元素的默认构造函数
  3. 返回指向第一个元素的指针
  4. 与静态数组一样,构造函数会被调用n次

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文