对象
是类和结构体的实例。
对象具有状态和行为,其中状态由对象的属性(或称为成员变量)表示,而行为则由对象的方法(或称为成员函数)定义。
#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;
}