1. 如果类A是一个空类,那么sizeof(A)的值为多少?
在C++中,即使是一个空类(即一个没有任何数据成员和成员函数的类),sizeof 还是会返回一个大于0的值。这是因为,即便是空类,也需要有一种方式来识别其实例。因此,C++标准规定,空类的大小至少为1字节。
以代码为例:
- class A { };
- std::cout << sizeof(A) << std::endl;
- //这段代码将会输出 1,意味着空类 A 的大小是1字节。
2.覆盖和重载之间有什么区别?
“覆盖”和”重载”在C++面向对象编程中是两个非常重要的概念,它们的区别如下:
- class Example {
- public:
- void func(int a) { /*...*/ } // 第一个版本的func函数
- void func(double a) { /*...*/ } // 第二个版本的func函数,参数是双精度浮点数
- };
- 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是基类,Dog和Cat是派生类。makeSound()函数在基类中被声明为虚函数,并在派生类中进行了重定义。当使用基类指针指向派生类对象并调用makeSound()函数时,根据实际对象的类型,将执行相应派生类中的函数。这就展现了多态性的特性。
多态性使得程序能够根据实际对象的类型来动态地调用相应的函数,提供了灵活性和可扩展性。通过使用虚函数和多态,我们可以编写更具通用性和可维护性的代码。
5.请你来说一下C++中struct和class的区别
在C++中,struct和class是用于定义类的关键字,它们之间的主要区别在于默认的访问权限和继承方式。
struct中,默认的访问权限是public,也就是说,struct中的成员变量和成员函数默认是可以被外部访问的。而在class中,默认的访问权限是private,也就是说,class中的成员变量和成员函数默认是只能在类的内部访问的。下面是一个示例来说明这一点:
- struct MyStruct {
- int publicVariable; // 默认为public
- private:
- int privateVariable;
- };
-
- class MyClass {
- int privateVariable; // 默认为private
- public:
- int publicVariable;
- };
struct来说,默认的继承方式是public继承,而对于class来说,默认的继承方式是private继承。下面是一个示例来说明这一点:
- struct BaseStruct {
- int x;
- };
-
- struct DerivedStruct : BaseStruct { // 默认为public继承
- int y;
- };
-
- class BaseClass {
- int x;
- };
-
- class DerivedClass : BaseClass { // 默认为private继承
- int y;
- };
除了上述区别之外,struct和class在其他方面是相似的,它们都可以拥有成员变量和成员函数,并且都可以用于定义对象。选择使用struct还是class取决于你对类的设计意图和数据封装的需求,以及个人或团队的编程风格习惯。