C++基础——类(进阶)

对象

是类和结构体的实例。

对象具有状态和行为,其中状态由对象的属性(或称为成员变量)表示,而行为则由对象的方法(或称为成员函数)定义。

#include <iostream>  
#include <string>    
// 定义一个类  
class Dog 
{  
public:  
    // 成员变量(对象的属性)  
    std::string name;  
    int age;  
    // 构造函数  
    Dog(std::string a, int b) : name(name), age(age) {}    
    // 成员函数(对象的行为)  
    void bark() 
    {  
        std::cout << name << " is barking!" << std::endl;  
    }  
};  
  
int main() 
{  
    // 创建一个Dog对象  
    Dog myDog("wuwu", 3);  
  
    // 访问对象的属性  
    std::cout << "Dog name: " << myDog.name << std::endl;  
    std::cout << "Dog age: " << myDog.age << std::endl;  
  
    // 调用对象的方法  
    myDog.bark();  
  
    return 0;  
}

构造函数初始化列表

 C++的构造函数初始化列表是一种特殊语法结构,它出现在构造函数定义的冒号(:)后面,直接跟在构造函数声明之后。

举个例子

class Student 
{
private:
    string name;
    int age;
public:
    Student(std::string n, int a) : name(n), age(a) { }
};

初始化列表用于在构造函数执行其主体代码之前,初始化类的成员变量。

这是因为某些成员(如const成员或引用成员)必须在它们的生命期内一开始就得到初始化,而不能通过构造函数主体内的赋值操作来完成初始化。

举个例子

//如果在类的中有const的数据需要赋值那就要需要使用构造函数初始化列表

class Student 
{
private:
    string name;
    int age;
    const double long; 
public:
    Student(string n, int a, double g) : name(n), age(a), long(g) { }
};

静态成员

静态数据成员 

存储:

静态数据成员存储在全局数据区,而不是每个对象的堆栈或堆中。这意味着,无论创建了多少个类的对象,静态数据成员都只会被分配一次存储空间,并且所有对象共享这同一个静态数据成员

生命周期:

静态数据成员在程序开始执行之前进行初始化,直到程序结束才释放,其生存期贯穿整个程序运行期间。

初始化:

静态数据成员必须进行初始化,通常在类声明之后,任何函数定义之前的地方进行显式初始化。

在类外进行初始化:

#include<iostream>
class book
{
public:
	inline static int tatalCount;
};

inline static int tatalCount=0;

int main()
{
    book a;
	std::cout << book::tatalCount << std::endl;
    std::cout << a.tatalCount << std::endl;
	return 0;
}

//结果是
0
0

在类内进行初始化:

#include<iostream>
class book
{
public:
	inline static int tatalCount{ 0 };
    //或者写成 static inline int tatalCount{ 0 }
};

int main()
{
    book a;
	std::cout << book::tatalCount << std::endl;
    std::cout << a.tatalCount << std::endl;
	return 0;
}

//结果是
0
0

访问权限: 

在类中对于不同的访问权限访问的方式不同

如果它是public,则可以直接使用类名加::进行访问或者使用类对象 进行访问。(如上面例子)

如果它是protected或private,虽然不能在类外部的普通作用域直接通过类名访问,但可以在类的友元函数、友元类或派生类(对于protected)中通过类名::静态成员名来访问。

用途:

静态数据成员常用于表示类的所有对象共享的属性,比如统计类的实例数量、记录全局状态等。

静态成员函数 

无this指针:

静态成员函数不与任何对象关联,因此它们不包含 this 指针,无法访问非静态的数据成员。

访问权限:

静态成员函数可以访问静态数据成员,但不能直接访问非静态成员。

静态成员函数在类外部的可用性也与在类内定义有关。

公共静态成员函数可以直接通过类名调用,如类名::静态成员函数名。

受保护或私有的静态成员函数不能在类外部的常规作用域直接调用,但可以在类的友元函数、友元类或满足访问条件的派生类中通过类名调用。

用途:

静态成员函数常用于提供与类相关的操作,这些操作不需要依赖于类的具体对象状态,例如工厂方法、工具函数或者是处理静态数据成员的方法。

举一个例子

#include <iostream>

class Student 
{
public:
    // 静态数据成员,用于统计学生总数
    static int totalStudents;

    // 构造函数,每次创建对象时增加学生总数
    Student() {
        ++totalStudents;
    }

    // 析构函数,销毁对象时不会减少学生总数(实际应用中可能需要考虑)
    ~Student() {}

    // 静态成员函数,返回当前学生总数
    static int getTotalStudents() {
        return totalStudents;
    }

private:
    // 其他类成员...
};

// 在类外部对静态数据成员进行初始化
int Student::totalStudents = 0;

int main() {
    Student s1;  // 创建一个学生对象,此时 totalStudents = 1
    Student s2;  // 创建第二个学生对象,此时 totalStudents = 2

    std::cout << "Total number of students: " << Student::getTotalStudents() <<std::endl;  // 输出 2

    return 0;
}

友元

在C++中,友元(Friend)是一种特殊的访问权限修饰符,它打破了面向对象编程中的封装性原则,允许一个类或函数访问另一个类的私有(private)和保护(protected)成员。

这种访问控制机制是在类的定义内部使用 friend 关键字来声明的。

友元函数:

一个非成员函数可以声明为某个类的友元,这样该函数就可以直接访问该类的所有成员,包括私有和受保护成员。

class MyClass 
{
private:
    int secretData;
public:
    friend void showSecret(MyClass& mc); // 声明showSecret函数为友元函数
};

void showSecret(MyClass& mc) 
{
    cout << mc.secretData; // 友元函数能直接访问MyClass的私有成员secretData
}

友元类:

一个类可以声明另一个类为其友元,这意味着整个友元类可以访问本类的所有私有和受保护成员。

class FriendClass;
class MyClass 
{
private:
    int privateVar;
public:
    friend class FriendClass; // 声明FriendClass为友元类
};

class FriendClass 
{
public:
    void accessPrivate(MyClass& obj) 
    {
        obj.privateVar = 42; // 友元类可以直接访问MyClass的私有成员privateVar
    }
};

友元关系是单向的,且不具备传递性。

如果类A是类B的友元,并不意味着类B也是类A的友元,同时类A的友元也不是类B的友元。

友元提供了灵活性,但过度使用会破坏封装性,降低代码的安全性和可维护性,因此在实际编程中应当谨慎使用。

类模板

类模板提供了一种方式来创建可以处理任何数据类型的类,而不仅仅是预定义的数据类型。

类模板的定义以template<typename T>或template<class T>开始,其中T是一个占位符类型参数,它将在实例化模板时被实际的数据类型所替代。

多个类如果仅仅是数据类型不同,则可以定义成类模板。

#include <iostream>  
  
// 定义一个类模板  
template<typename T>  
class Array {  
private:  
    T* arr;  
    int size;  
  
public:  
    // 构造函数  
    Array(T arr[], int s);  
  
    // 析构函数  
    ~Array();  
  
    // 成员函数  
    void print();  
};  
  
// 类模板的成员函数实现(定义在类模板的外部)  
template<typename T>  
Array<T>::Array(T arr[], int s) {  
    size = s;  
    this->arr = new T[s];  
    for (int i = 0; i < size; i++) {  
        this->arr[i] = arr[i];  
    }  
}  
  
template<typename T>  
Array<T>::~Array() 
{  
    delete[] arr;  
}  
  
template<typename T>  
void Array<T>::print() 
{  
    for (int i = 0; i < size; i++) 
    {  
        std::cout << arr[i] << " ";  
    }  
    std::cout << std::endl;  
}  
  
int main() 
{  
    // 整数数组  
    int intArr[] = {1, 2, 3, 4, 5};  
    Array<int> intArray(intArr, 5);  
    intArray.print();  
  
    // 浮点数数组  
    double doubleArr[] = {1.1, 2.2, 3.3, 4.4, 5.5};  
    Array<double> doubleArray(doubleArr, 5);  
    doubleArray.print();  
  
    return 0;  
}

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值