当前位置:首页 > 公众号精选 > 码农爱学习

本篇来继续补充介绍面向对象的一些概念,并以C++代码进行举例。

1 构造函数

构造函数是面向对象编程中的一个重要概念,用于在创建对象时初始化对象的状态。

1.1 构造函数的运行时机 

构造函数在创建对象时自动调用。

当实例化一个类的对象时,构造函数会被自动执行。构造函数的运行时机是在对象的内存分配完成之后。

class MyClass 
{

public:
    MyClass() 
    {
        cout << "Constructor is called!" << endl;
    }
};

int main() 
{
    MyClass obj;  // 实例化一个对象,构造函数在此处被调用
    return 0;
}

1.2 构造函数中的内容 

构造函数通常用于初始化对象的成员变量或执行一些必要的设置操作。

你可以在构造函数中为对象的属性赋初值,或调用其他方法来初始化对象的使用环境。

class Person 
{

public:
    std::string name;
    int         age;

    // 构造函数
    Person(std::string name, int age) 
    {
        this->name = name;
        this->age  = age;
    }

    void display() 
    
{
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};

int main() 
{
    Person person("Alice", 30); // 实例化对象时,通过构造函数传入参数进行初始化
    person.display();           // 输出: Name: Alice, Age: 30
    return0;
}

1.3 默认构造函数 

如果你没有为类定义任何构造函数,编译器会自动为你生成一个默认构造函数。默认构造函数没有参数,并且不执行任何操作。

如果你定义了任何构造函数(无论是否有参数),编译器将不再提供默认构造函数。

class MyClass 
{

    // 没有自定义构造函数,则编译器会自动生成一个默认构造函数
};

int main() 
{
    MyClass obj;  // 实例化对象时,使用默认构造函数
    return 0;
}

1.4 使用多个构造函数 

一个类可以有多个构造函数,这被称为构造函数的重载(Overloading)。

每个构造函数可以有不同的参数列表,以便在创建对象时提供不同的初始化方式。

class Person 
{

public:
    std::string name;
    int         age;
    
    Person() // 无参数的构造函数
    {
        this->name = "Unknown";
        this->age  = 0;
    }
    
    Person(std::string name) // 带一个参数的构造函数
    {
        this->name = name;
        this->age  = 0;
    }

    Person(std::string name, int age) // 带两个参数的构造函数
    {
        this->name = name;
        this->age  = age;
    }

    void display() 
    
{
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};

int main() 
{
    Person person1;                 // 使用无参数的构造函数
    Person person2("Bob");          // 使用带一个参数的构造函数
    Person person3("Charlie", 25);  // 使用带两个参数的构造函数

    person1.display();  // 输出: Name: Unknown, Age: 0
    person2.display();  // 输出: Name: Bob, Age: 0
    person3.display();  // 输出: Name: Charlie, Age: 25

    return0;
}

2 错误处理

错误处理是编程中非常重要的一部分,它决定了程序在遇到问题时如何响应。

处理异常可以有如下选择:

  • 忽略问题(不推荐)
  • 检查潜在问题,发现问题时及时终止
  • 检查潜在问题,捕获错误并试图修复该问题
  • 抛出异常(推荐)

2.1 忽略问题 

忽略问题是最简单的错误处理方式,但通常不推荐使用,因为它可能导致程序在后续运行中出现不可预知的错误。

int divide(int a, int b) 
{
    return a / b;  // 如果b为0,程序会崩溃
}

int main() 
{
    int result = divide(10, 0);  // 忽略除零错误
    std::cout << "Result: " << result << std::endl;  // 程序可能崩溃
    return 0;
}

2.2 检查并终止程序 

在检测到错误时,程序可以选择终止运行。这种方式适用于严重错误,无法继续执行的情况。

#include 
#include   // 用于 exit()

int divide(int a, int b) 
{
    if (b == 0) 
    {
        std::cerr << "Error: Division by zero!" << std::endl;
        exit(EXIT_FAILURE);  // 调用exit终止程序
    }
    return a / b;
}

int main() 
{
    int result = divide(10, 0);  // 检测到错误,程序终止
    std::cout << "Result: " << result << std::endl;  // main函数不会执行到这里
    return0;
}

2.3 检查并尝试修复 

在某些情况下,程序可以检测到错误并尝试修复问题,或者提供替代方案。

int divide(int a, int b) 
{
    if (b == 0) 
    {
        std::cout << "Warning: Division by zero! Returning 0 instead." << std::endl;
        return0;  // 尝试修复问题
    }
    return a / b;
}

int main() 
{
    int result = divide(10, 0);  // 检测到错误,尝试修复
    std::cout << "Result: " << result << std::endl;  // 输出: Result: 0
    return0;
}

2.4 抛出异常 

抛出异常是一种更灵活的错误处理机制。

它允许程序在检测到错误时抛出一个异常,并由调用者决定如何处理。

int divide(int a, int b)
{
    if (b == 0) 
    {
        throw runtime_error("Division by zero!");  // 抛出异常
    }
    return a / b;
}

int main() 
{
    try
    {
        int result = divide(10, 0);  // 尝试执行可能抛出异常的代码
        std::cout << "Result: " << result << std::endl;
    } 
    catch (const runtime_error& e) 
    {
        std::cerr << "Error: " << e.what() << std::endl;  // 捕获并处理异常
    }
    return0;
}

3 作用域

3.1 局部属性 

局部属性是指在函数或方法内部定义的变量,它们的作用域仅限于该函数或方法。

局部属性在函数或方法执行完毕后会被销毁,无法在外部访问。

void myFunction() 
{
    int localVar = 10; // 局部变量
    std::cout << "Local variable: " << localVar << std::endl;
}

int main() 
{
    myFunction();
    // std::cout << localVar; // 这里会报错,因为 localVar 是局部变量,无法在函数外部访问
    return 0;
}

3.2 对象属性 

对象属性是指类的成员变量,它们属于类的实例,可以通过对象访问。

class MyClass 
{

public:m_
    int m_objectAttr; // 对象属性

    MyClass(int value) : m_objectAttr(value) {} // 构造函数初始化对象属性
};

int main() 
{
    MyClass obj(20); // 创建对象
    std::cout << "Object attribute: " << obj.m_objectAttr << std::endl; // 输出: 20
    return 0;
}

3.3 类属性 

C++ 中没有直接的“类属性”概念,但可以通过 static 关键字实现类似的功能。

注意:静态成员变量属于类本身,而不是类的实例。

class MyClass 
{

public:
    staticint classAttr; // 类属性(静态成员变量)
};

int MyClass::classAttr = 30; // 静态成员变量需要在类外初始化

int main() 
{
    std::cout << "Class attribute: " << MyClass::classAttr << std::endl; // 输出: 30

    MyClass obj;
    std::cout << "Class attribute via object: " << obj.classAttr << std::endl; // 输出: 30
    return0;
}

4 操作符重载

C++ 允许通过重载操作符来定义类的实例如何响应标准操作符(如 +, -, *, / 等)。

// 二维数据点类
class Point 
{

public:
    int x, y;

    Point(int x = 0, int y = 0) : x(x), y(y) {}

    // 重载 + 操作符
    Point operator+(const Point& other) 
    {
        return Point(x + other.x, y + other.y);
    }

    // 重载 << 操作符以方便输出
    friendstd::ostream& operator<<(std::ostream& os, const Point& p) 
    {
        os << "Point(" << p.x << ", " << p.y << ")";
        return os;
    }
};

int main() 
{
    Point p1(1, 2);
    Point p2(3, 4);
    Point p3 = p1 + p2; // 使用重载的 + 操作符
    std::cout << p3 << std::endl; // 输出: Point(4, 6)
    return0;
}

5 多重继承

C++ 支持多重继承,即一个类可以从多个父类继承属性和方法。

class A
{

public:
    void methodA() 
    
{
        cout << "Method A" << endl;
    }
};

class B 
{

public:
    void methodB() 
    
{
        cout << "Method B" << endl;
    }
};

class C :public A, public B { // 多重继承,C既继承A,又继承B
};

int main() 
{
    C obj;
    obj.methodA(); // 输出: Method A
    obj.methodB(); // 输出: Method B
    return0;
}

7 总结

本篇来继续补充介绍面向对象的一些概念:构造函数、错误处理、作用域、操作符重、多重继承等,并以C++代码进行举例。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭