Day4: 5道C++ 面向对象高频题整理

本文详细解释了C++中空类的sizeof计算,函数重载与覆盖的区别,拷贝构造函数与赋值运算符的功能,虚函数和多态的运用,以及struct与class的差异。这些知识点有助于理解面向对象编程的核心概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 如果类A是一个空类,那么sizeof(A)的值为多少?

在C++中,即使是一个空类(即一个没有任何数据成员和成员函数的类),sizeof 还是会返回一个大于0的值。这是因为,即便是空类,也需要有一种方式来识别其实例。因此,C++标准规定,空类的大小至少为1字节。

以代码为例:

class A { };
std::cout << sizeof(A) << std::endl;
//这段代码将会输出 1,意味着空类 A 的大小是1字节。

2.覆盖和重载之间有什么区别?

“覆盖”和”重载”在C++面向对象编程中是两个非常重要的概念,它们的区别如下:

  • 函数重载(Overloading):这发生在同一个类中,当你有两个或更多数量的函数拥有相同的名字但是参数列表不同(比如参数数量不同,参数类型不同,或者参数顺序不同)时,我们就称之为函数重载。例如:
class Example {
public:
    void func(int a) { /*...*/ } // 第一个版本的func函数
    void func(double a) { /*...*/ } // 第二个版本的func函数,参数是双精度浮点数
};
  • 函数覆盖(Overriding):这发生在继承关系中,当子类有一个和父类完全相同的函数(函数名相同,参数列表相同,返回类型也相同),我们就称之为函数覆盖。子类覆盖父类的函数是为了提供不同的实现,这是多态性的一个重要体现。例如:
class Base {
public:
    virtual void func() { /*...*/ } // 父类的func函数
};

class Derived : public Base {
public:
    void func() override { /*...*/ } // 子类的func函数,覆盖了父类的func函数
};

在这个例子中,如果你有一个指向Derived类对象的Base类指针,并且通过这个指针调用func函数,将会执行Derived类的func函数,这就是多态性的体现。

3.拷贝构造函数和赋值运算符重载之间有什么区别?

拷贝构造函数赋值运算符重载都用于在C++中复制对象,但是它们的用途和执行方式有所不同。

  • 拷贝构造函数:拷贝构造函数在一个新对象创建的时候被调用,用于将一个已存在的对象的状态(也就是成员变量的值)复制到新对象。例如:
    class Example {
    public:
        int value;
        Example(int val) : value(val) { } // 常规构造函数
        Example(const Example& other) : value(other.value) { } // 拷贝构造函数
    };
    
    Example a(10); // 使用常规构造函数
    Example b(a); // 使用拷贝构造函数,b的value值将会是10
    

  • 赋值运算符重载:赋值运算符重载在一个已经存在的对象需要被赋予另一个已经存在的对象的状态时被调用。例如:

class Example {
public:
    int value;
    Example(int val) : value(val) { } // 常规构造函数
    Example& operator=(const Example& other) { // 赋值运算符重载
        if (this != &other) { // 防止自我赋值
            value = other.value;
        }
        return *this;
    }
};

Example a(10); // 使用常规构造函数
Example b(20); // 使用常规构造函数
b = a; // 使用赋值运算符重载,b的value值将会是10

注意,赋值运算符重载通常需要注意自我赋值的情况,并且应返回对象本身的引用,这样可以支持连续赋值如a = b = c

总的来说,拷贝构造函数用于初始化新对象,而赋值运算符重载用于已存在的对象。

4.对虚函数和多态的理解

虚函数和多态是C++面向对象编程中非常重要的概念,它们之间有着密切的关联。

虚函数是在基类中声明的带有virtual关键字的成员函数。它允许在派生类中进行函数的重定义,从而实现多态性。当基类指针或引用指向派生类对象,并调用虚函数时,实际执行的是派生类中重定义的函数。这种行为称为动态绑定或后期绑定。

以下是一个示例:

class Animal {
public:
    virtual void makeSound() {
        cout << "Animal makes a sound." << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {
        cout << "Dog barks." << endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        cout << "Cat meows." << endl;
    }
};

int main() {
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();

    animal1->makeSound(); // 输出:Dog barks.
    animal2->makeSound(); // 输出:Cat meows.

    delete animal1;
    delete animal2;

    return 0;
}

在上面的例子中,Animal是基类,DogCat是派生类。makeSound()函数在基类中被声明为虚函数,并在派生类中进行了重定义。当使用基类指针指向派生类对象并调用makeSound()函数时,根据实际对象的类型,将执行相应派生类中的函数。这就展现了多态性的特性。

多态性使得程序能够根据实际对象的类型来动态地调用相应的函数,提供了灵活性和可扩展性。通过使用虚函数和多态,我们可以编写更具通用性和可维护性的代码。

5.请你来说一下C++中struct和class的区别

在C++中,structclass是用于定义类的关键字,它们之间的主要区别在于默认的访问权限和继承方式。

  • 默认的访问权限:在struct中,默认的访问权限是public,也就是说,struct中的成员变量和成员函数默认是可以被外部访问的。而在class中,默认的访问权限是private,也就是说,class中的成员变量和成员函数默认是只能在类的内部访问的。

下面是一个示例来说明这一点:

struct MyStruct {
    int publicVariable; // 默认为public
private:
    int privateVariable;
};

class MyClass {
    int privateVariable; // 默认为private
public:
    int publicVariable;
};
  • 继承方式:在C++中,类可以通过继承来扩展其功能。对于struct来说,默认的继承方式是public继承,而对于class来说,默认的继承方式是private继承。

下面是一个示例来说明这一点:

struct BaseStruct {
    int x;
};

struct DerivedStruct : BaseStruct { // 默认为public继承
    int y;
};

class BaseClass {
    int x;
};

class DerivedClass : BaseClass { // 默认为private继承
    int y;
};

除了上述区别之外,structclass在其他方面是相似的,它们都可以拥有成员变量和成员函数,并且都可以用于定义对象。选择使用struct还是class取决于你对类的设计意图和数据封装的需求,以及个人或团队的编程风格习惯。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值