清远做网站的,广告公司接单软件,网站小功能,网站建设 浏览器兼容文章目录 初始化列表语法结构定义和使用案例初始化列表初始化常量成员#xff1a; 注意事项 运算符重载加法运算符重载语法结构示例注意事项 减法运算符重载语法结构示例注意事项 等于运算符重载等于运算符 的重载语法示例注意事项 大于运算符重载大于运算符 的重载语法… 文章目录 初始化列表语法结构定义和使用案例初始化列表初始化常量成员 注意事项 运算符重载加法运算符重载语法结构示例注意事项 减法运算符重载语法结构示例注意事项 等于运算符重载等于运算符 的重载语法示例注意事项 大于运算符重载大于运算符 的重载语法示例注意事项 运算符重载前置加加运算符 (operand)语法结构和定义示例注意事项前置加加运算符 后置加加运算符 (operand)语法结构和定义示例注意事项后置加加运算符 运算符重载语法结构和定义示例注意事项 静态变量和函数静态变量静态成员变量语法结构和定义案例注意事项 静态函数静态成员函数语法结构和定义案例注意事项 友元友元函数语法结构和定义案例注意事项 友元类声明案例注意事项 初始化列表
初始化列表initializer list在C中是一种用来初始化类、结构体、数组等数据结构的语法结构。它可以在定义变量时直接初始化也可以在构造函数中初始化成员变量。
语法结构
ConstructorName(Type1 arg1, Type2 arg2, ...) : member1(arg1), member2(arg2), ... {// constructor body
}这里是初始化列表的组成部分
ConstructorName构造函数的名称与类名相同。
参数列表构造函数可以接受的参数列表这些参数用来初始化类的成员变量。
冒号:初始化列表以冒号开头。
成员初始化每个成员初始化的语法是 memberName(arg)其中 memberName 是类的成员变量名arg 是用来初始化该成员变量的值。
构造函数体可选的构造函数体用来执行更多的初始化操作或者其他逻辑。
定义和使用
在变量定义时的初始化
int arr[3] {1, 2, 3}; // 初始化数组
std::vectorint vec {4, 5, 6};
// 初始化向量在构造函数中的初始化
class Example {
public:int x;double y;// 构造函数使用初始化列表Example(int a, double b) : x(a), y(b) {// 构造函数体}
};在上面的例子中Example类的构造函数使用初始化列表来初始化成员变量x和y。
案例
初始化列表初始化成员变量
class Point {
private:int x, y;public:// 使用初始化列表初始化成员变量Point(int x_val, int y_val) : x(x_val), y(y_val) {// 可选的构造函数体}
};初始化列表初始化常量成员
class Circle {
private:const double pi;double radius;public:// 初始化常量成员 piCircle(double r) : pi(3.14159), radius(r) {// 构造函数体}
};注意事项
初始化顺序初始化列表中的成员变量初始化顺序与它们在类中声明的顺序一致而不是它们在初始化列表中出现的顺序。
初始化常量成员常量成员变量如上例中的pi只能通过初始化列表来初始化不能在构造函数体内赋值。
成员变量类型初始化列表只能用于初始化非静态成员变量静态成员变量不能在构造函数初始化列表中初始化。
没有默认值如果类的某个成员变量没有在初始化列表中初始化它将使用默认的构造函数进行初始化如果有的话。
效率初始化列表的使用可以避免不必要的默认构造和拷贝操作因此在效率上可能比在构造函数体内进行初始化更好。
运算符重载
加法运算符重载
语法结构
加法运算符 的重载语法如下
ReturnType operator(const ClassName obj) {// 加法运算的实现// 可以访问对象的成员变量和方法return ReturnType(result);
}其中
ReturnType是加法运算的结果类型可以是对象、引用或者基本数据类型。operator是加法运算符的函数名用于重载加法运算符。ClassName是定义加法运算符的类名。const ClassName obj是右操作数即用于与当前对象进行加法运算的对象。
函数体内部实现了加法的逻辑并返回加法结果。
示例
下面是一个使用加法运算符重载的示例
#include iostreamclass Complex {
private:double real;double imag;public:Complex(double r 0.0, double i 0.0) : real(r), imag(i) {}// 重载加法运算符Complex operator(const Complex other) {Complex temp;temp.real real other.real;temp.imag imag other.imag;return temp;}void display() {std::cout real imag i std::endl;}
};int main() {Complex c1(2.3, 4.5);Complex c2(3.4, 5.6);Complex c3;c3 c1 c2; // 使用重载的运算符std::cout Sum of ;c1.display();std::cout and ;c2.display();std::cout is ;c3.display();return 0;
}在这个例子中Complex类表示复数重载了加法运算符 使得可以对两个 Complex 对象进行相加操作。在 main() 函数中创建了两个复数对象 c1 和 c2然后通过 c1 c2 进行加法运算并将结果赋给 c3。
注意事项
参数类型通常情况下加法运算符重载的参数应当是同类的对象或者可以转换为同类对象的类型。
返回类型加法运算符重载函数通常返回一个新的对象代表加法的结果。
修改对象一般情况下不应该在加法运算符重载中修改参数对象本身的状态而是应当返回一个新的对象表示结果。
友元函数如果需要在加法运算符重载函数中访问私有成员变量可以将其声明为友元函数。
连续加法重载的加法运算符也支持链式调用例如 c1 c2 c3。
保持语义一致性加法运算符重载的结果应当符合加法的数学意义并且不应引入歧义或者不合理的行为。
减法运算符重载
当涉及到在 C 中重载减法运算符 - 时它与重载加法运算符类似允许用户定义对自定义类型的减法操作。下面是减法运算符重载的语法结构、示例和一些注意事项
语法结构
减法运算符 - 的重载语法如下
ReturnType operator-(const ClassName obj) {// 减法运算的实现// 可以访问对象的成员变量和方法return ReturnType(result);
}其中
ReturnType是减法运算的结果类型可以是对象、引用或者基本数据类型。operator-是减法运算符的函数名用于重载减法运算符。ClassName是定义减法运算符的类名。const ClassName obj是右操作数即用于与当前对象进行减法运算的对象。
函数体内部实现了减法的逻辑并返回减法结果。
示例
下面是一个使用减法运算符重载的示例假设我们仍然使用复数 Complex 类
#include iostreamclass Complex {
private:double real;double imag;public:Complex(double r 0.0, double i 0.0) : real(r), imag(i) {}// 重载减法运算符-Complex operator-(const Complex other) {Complex temp;temp.real real - other.real;temp.imag imag - other.imag;return temp;}void display() {std::cout real imag i std::endl;}
};int main() {Complex c1(5.7, 8.4);Complex c2(3.2, 1.6);Complex c3;c3 c1 - c2; // 使用重载的-运算符std::cout Difference of ;c1.display();std::cout and ;c2.display();std::cout is ;c3.display();return 0;
}在这个示例中Complex 类再次表示复数重载了减法运算符 -允许对两个 Complex 对象进行减法操作。在 main() 函数中创建了两个复数对象 c1 和 c2然后通过 c1 - c2 进行减法运算并将结果赋给 c3。
注意事项
参数类型和返回类型与加法运算符类似减法运算符重载函数的参数应当是同类的对象或者可以转换为同类对象的类型返回类型通常是表示减法结果的新对象。
对象状态遵循良好的实践不要在减法运算符重载中修改参数对象本身的状态而是应当返回一个新的对象表示结果。
友元函数如有需要可以将减法运算符重载函数声明为友元函数以访问私有成员变量。
连续减法重载的减法运算符同样支持链式调用例如 c1 - c2 - c3。
语义一致性确保减法运算符重载的行为符合减法的数学定义避免引入歧义或者不合理的操作。
等于运算符重载
当你在 C 中重载等于运算符 你可以自定义两个对象相等的条件。这种重载允许你用更符合你自定义类型特性的方式来比较对象的相等性。
等于运算符 的重载语法
等于运算符的重载语法如下
bool operator(const ClassName obj) const {// 判断当前对象和参数对象是否相等的逻辑// 返回 true 表示相等返回 false 表示不相等
}其中
bool等于运算符需要返回一个布尔值表示对象是否相等。operator是等于运算符的函数名用于重载等于运算符。ClassName是定义等于运算符的类名。const ClassName obj是右操作数即用于与当前对象进行比较的对象。
const 关键字和成员函数后面的 const 保证了该成员函数不会修改对象的成员变量。
示例
假设我们继续使用复数 Complex 类来示范等于运算符的重载
#include iostreamclass Complex {
private:double real;double imag;public:Complex(double r 0.0, double i 0.0) : real(r), imag(i) {}// 重载等于运算符bool operator(const Complex other) const {return (real other.real) (imag other.imag);}void display() const {std::cout real imag i std::endl;}
};int main() {Complex c1(2.0, 3.0);Complex c2(2.0, 3.0);Complex c3(4.0, 1.5);if (c1 c2) {std::cout c1 and c2 are equal. std::endl;} else {std::cout c1 and c2 are not equal. std::endl;}if (c1 c3) {std::cout c1 and c3 are equal. std::endl;} else {std::cout c1 and c3 are not equal. std::endl;}return 0;
}在这个示例中Complex 类重载了等于运算符 以便比较两个复数对象的实部和虚部是否相等。在 main() 函数中创建了三个复数对象 c1、c2 和 c3并使用 c1 c2 和 c1 c3 来演示等于运算符的使用。
注意事项
语义一致性确保你的等于运算符重载与你的类型的语义一致。比如在复杂类型中可能需要比较多个成员变量而不仅仅是一个。
友元函数如有必要等于运算符重载可以声明为友元函数以便访问私有成员变量。
对称性等于运算符应当是对称的即 a b 应当和 b a 具有相同的效果。
大于运算符重载
大于运算符 的重载语法
大于运算符的重载语法与等于运算符类似它允许您自定义两个对象之间的大小比较条件。
bool operator(const ClassName obj) const {// 判断当前对象是否大于参数对象的逻辑// 返回 true 表示当前对象大于参数对象返回 false 表示不大于
}其中
bool大于运算符需要返回一个布尔值表示当前对象是否大于参数对象。operator是大于运算符的函数名用于重载大于运算符。ClassName是定义大于运算符的类名。const ClassName obj是右操作数即用于与当前对象进行比较的对象。
const 关键字和成员函数后面的 const 保证了该成员函数不会修改对象的成员变量。
示例
继续使用之前的 Complex 类来演示大于运算符的重载
#include iostreamclass Complex {
private:double real;double imag;public:Complex(double r 0.0, double i 0.0) : real(r), imag(i) {}// 重载大于运算符bool operator(const Complex other) const {// 比较复数的模模长double this_modulus real * real imag * imag;double other_modulus other.real * other.real other.imag * other.imag;return this_modulus other_modulus;}void display() const {std::cout real imag i std::endl;}
};int main() {Complex c1(2.0, 3.0);Complex c2(4.0, 1.5);if (c1 c2) {std::cout c1 is greater than c2. std::endl;} else {std::cout c1 is not greater than c2. std::endl;}return 0;
}在这个示例中Complex 类重载了大于运算符 以便比较两个复数对象的模即模长是否满足大于关系。在 main() 函数中创建了两个复数对象 c1 和 c2并使用 c1 c2 来演示大于运算符的使用。
注意事项
语义一致性确保您的大于运算符重载与您的类型的语义一致。比如在复杂类型中可能需要比较多个成员变量而不仅仅是一个。
友元函数如有必要大于运算符重载可以声明为友元函数以便访问私有成员变量。
对称性大于运算符应当是对称的即 a b 应当和 b a 具有相同的效果。
运算符重载
当我们讨论 “” 运算符在 C 中的重载时通常会涉及到两种形式前置加加运算符operand和后置加加运算符operand。下详细解释这两种运算符的重载语法结构、定义、案例和注意事项。
前置加加运算符 (operand)
语法结构和定义
前置加加运算符 的重载形式如下
ReturnType operator() {// 增加操作数的值// 返回增加后的操作数
}其中
ReturnType是返回值的类型通常是引用类型以便支持连续操作。operator是前置加加运算符的函数名用于重载前置加加运算符。()代表这是一个函数调用。
操作数被隐式地作为当前对象this传递给运算符函数。
示例
以下是一个示例演示了如何重载前置加加运算符
#include iostreamclass Integer {
private:int value;public:Integer(int v 0) : value(v) {}// 重载前置加加运算符Integer operator() {value;return *this;}void display() const {std::cout Value: value std::endl;}
};int main() {Integer num(5);num; // 使用前置加加运算符num.display(); // 输出 Value: 6return 0;
}在这个示例中Integer 类重载了前置加加运算符 使得可以直接对 Integer 类型的对象进行自增操作。
注意事项前置加加运算符
返回类型通常应该返回引用类型 ReturnType以支持链式调用和修改对象本身。
副作用前置加加运算符会直接修改对象的值应该确保操作的一致性和正确性。
成员函数声明通常应将前置加加运算符声明为类的成员函数以便访问对象的私有成员变量。
后置加加运算符 (operand)
语法结构和定义
后置加加运算符 的重载形式如下
ReturnType operator(int) {// 创建一个副本以便于后续返回// 增加操作数的值// 返回之前的副本
}其中
ReturnType是返回值的类型通常是原始类型非引用。operator是后置加加运算符的函数名用于重载后置加加运算符。(int)这是一个额外的参数但通常不使用该参数。
示例
以下是一个示例演示了如何重载后置加加运算符
#include iostreamclass Integer {
private:int value;public:Integer(int v 0) : value(v) {}// 重载后置加加运算符Integer operator(int) {Integer temp(value); // 创建一个副本value; // 增加操作数的值return temp; // 返回之前的副本}void display() const {std::cout Value: value std::endl;}
};int main() {Integer num(5);Integer old_num num; // 使用后置加加运算符num.display(); // 输出 Value: 6old_num.display(); // 输出 Value: 5return 0;
}在这个示例中Integer 类重载了后置加加运算符 返回原始值的副本并在返回之前增加了对象的值。
注意事项后置加加运算符
返回类型通常应该返回对象的原始类型而不是引用以避免悬挂引用问题。 参数后置加加运算符通常需要一个额外的 int 参数可以不使用用于区分前置和后置形式。 效率后置加加运算符需要创建一个对象的副本因此可能比前置加加运算符稍慢。
运算符重载
重载左移运算符 在 C 中常用于自定义类的输出格式使得类对象可以像内置类型一样直接输出到标准输出流如 std::cout。下面详细解释如何在 C 中重载左移运算符 。
语法结构和定义
左移运算符 的重载形式如下
ReturnType operator(std::ostream os, const YourClass obj) {// 输出 obj 到 ostream os 中return os; // 返回 ostream 对象
}其中
ReturnType通常是 std::ostream因为左移运算符重载的目的是为了支持链式输出。operator是左移运算符的函数名用于重载左移运算符。std::ostream os是输出流对象的引用如 std::cout。const YourClass obj是要输出的类对象的引用通常是常量引用以避免不必要的复制。
示例
以下是一个示例演示了如何重载左移运算符
#include iostreamclass Point {
private:int x;int y;public:Point(int x 0, int y 0) : x(x), y(y) {}// 重载左移运算符friend std::ostream operator(std::ostream os, const Point obj) {os Point( obj.x , obj.y );return os;}
};int main() {Point p1(3, 4);Point p2(-1, 8);std::cout Point p1: p1 std::endl;std::cout Point p2: p2 std::endl;return 0;
}在这个示例中Point 类重载了左移运算符 使得可以直接输出 Point 对象到标准输出流 std::cout 中。
注意事项
友元函数通常将左移运算符重载函数声明为类的友元函数以便访问类的私有成员变量。
返回类型应该返回 std::ostream 类型以支持链式输出。
引用参数对象参数应该是常量引用 const YourClass避免不必要的复制。
静态变量和函数
在C中静态变量静态成员变量和静态函数静态成员函数属于类的静态成员它们不依赖于类的实例而存在而是与类本身关联。以下是它们的语法结构、定义、案例和注意事项
静态变量静态成员变量
语法结构和定义
静态成员变量由关键字 static 声明通常在类的声明中定义但在类的定义外初始化。
定义格式为static type variable_name;
class MyClass {
public:static int count;// other members...
};// 类的定义外部初始化
int MyClass::count 0;案例
#include iostreamclass MyClass {
public:static int count;MyClass() {count;}
};int MyClass::count 0;int main() {MyClass obj1;MyClass obj2;MyClass obj3;std::cout Number of objects created: MyClass::count std::endl;return 0;
}输出
Number of objects created: 3注意事项 静态变量被所有类对象共享它们在程序的生命周期内只有一份实例。 静态成员变量必须在类的定义外部进行初始化。 可以通过类名和作用域解析运算符 :: 来访问静态成员变量如 MyClass::count。
静态函数静态成员函数
语法结构和定义
静态成员函数也由关键字 static 声明。
静态函数可以直接访问类的静态成员变量和其他静态成员函数但不能直接访问非静态成员变量和非静态成员函数。
定义格式为static return_type function_name(parameters);class MyClass {
public:static void staticFunction() {std::cout This is a static function. std::endl;}
};案例
#include iostreamclass MyClass {
public:static void staticFunction() {std::cout This is a static function. std::endl;}void normalFunction() {std::cout This is a normal function. std::endl;}
};int main() {MyClass::staticFunction();MyClass obj;obj.normalFunction();// Accessing static function through object (not recommended):obj.staticFunction(); // valid but not recommendedreturn 0;
}输出 This is a static function. This is a normal function. This is a static function. 注意事项 静态函数不能直接访问非静态成员变量或非静态成员函数因为它们没有隐含的 this 指针。 可以通过类名直接调用静态函数也可以通过对象调用静态函数但不推荐后者因为静态函数不依赖于具体对象。
友元
友元friend在C中是一种机制允许某些函数或类访问另一个类的私有成员。友元可以是一个函数、一个类、或者整个类中的所有函数。这种机制打破了C中的封装性因此需要谨慎使用。
友元函数
语法结构和定义
友元函数声明在目标类的内部但定义在类的外部。
友元函数的声明以关键字 friend 开始后面跟随函数原型。class MyClass {
private:int privateData;public:MyClass() : privateData(0) {}friend void friendFunction(MyClass obj);
};void friendFunction(MyClass obj) {// 友元函数可以访问目标类的私有成员obj.privateData 100;
}案例
#include iostreamclass MyClass {
private:int privateData;public:MyClass() : privateData(0) {}friend void friendFunction(MyClass obj);void displayPrivateData() {std::cout Private data: privateData std::endl;}
};void friendFunction(MyClass obj) {obj.privateData 100; // 可以访问私有成员 privateData
}int main() {MyClass obj;friendFunction(obj); // 调用友元函数obj.displayPrivateData(); // 输出 Private data: 100return 0;
}输出
Private data: 100注意事项
友元函数并不是目标类的成员函数它没有 this 指针因此不能直接访问类的成员。友元函数在访问目标类的私有成员时不受访问权限限制。友元函数的声明需要在目标类中进行但定义可以在类外部进行。 友元类 除了友元函数C还支持友元类即一个类可以将另一个类声明为自己的友元这样被声明的友元类就可以访问声明它为友元的类的所有成员包括私有成员。 友元类
声明
class FriendClass {
public:void accessMyClassPrivateData(MyClass obj) {obj.privateData 200; // 可以访问目标类的私有成员}
};class MyClass {
private:int privateData;friend class FriendClass; // 声明FriendClass为友元类public:MyClass() : privateData(0) {}void displayPrivateData() {std::cout Private data: privateData std::endl;}
};案例
#include iostreamclass FriendClass {
public:void accessMyClassPrivateData(MyClass obj) {obj.privateData 200; // 可以访问目标类的私有成员}
};class MyClass {
private:int privateData;friend class FriendClass; // 声明FriendClass为友元类public:MyClass() : privateData(0) {}void displayPrivateData() {std::cout Private data: privateData std::endl;}
};int main() {MyClass obj;FriendClass friendObj;friendObj.accessMyClassPrivateData(obj); // 通过友元类访问私有成员obj.displayPrivateData(); // 输出 Private data: 200return 0;
}输出 Private data: 200注意事项
友元类的声明会影响整个类的封装性因此应慎重考虑使用。友元关系是单向的声明了 A 类为 B 类的友元并不意味着 B 类也是 A 类的友元。友元关系不能被继承子类不能访问父类的友元。