C++学习总结

目录

1.如何定义一个类

2.如何定义类的构造函数和析构函数?

3.类的各成员函数的执行顺序是怎样的?

4.类组合时对象的构造顺序是怎样的?

5.如何存储和处理字符串?

6.头文件和头文件有何区别?

7.有几种方法来表示和处理数组元素?

8.如何在已有的类的基础上设计新的类?

9.基类和派生类对象的构造顺序是怎样的?

10.如何利用虚基类解决二义性问题?

11.在继承过程中,应该注意将适当的类设置为虚基类,如果不设置为虚基类,会有什么问题?

12.如何将一个运算符重载为类的成员函数?

13.如何将一个运算符重载为类的友元函数?

14.如何实现运行时刻的多态?


1.如何定义一个类

在C++中,定义一个类通常包括以下内容:

class ClassName{
public: // 访问修饰符,用于控制成员的访问权限
    // 成员变量
    // 成员函数
private:
    // 私有成员变量
    // 私有成员函数
protected:
    // 保护成员变量
    // 保护成员函数
};

其中,成员变量用于描述对象的属性,成员函数用于定义对象的行为。访问修饰符用于控制成员的访问权限,public表示该成员可以被任何对象访问,private表示只有该类的成员函数可以访问,protected表示该类的成员函数以及其子类的成员函数可以访问。

2.如何定义类的构造函数和析构函数?

构造函数用于在对象创建时进行初始化操作,析构函数用于在对象销毁时进行清理操作。定义构造函数和析构函数的语法如下:

class ClassName{
public:
    // 构造函数
    ClassName(参数列表){
        // 初始化操作
    }
    // 析构函数
    ~ClassName(){
        // 清理操作
    }
};

其中,构造函数的名称与类名相同,不需要返回值类型;析构函数的名称也与类名相同,前面加上波浪号(~)。

3.类的各成员函数的执行顺序是怎样的?

当创建一个对象时,类中的成员函数执行顺序如下:

  1. 构造函数(从基类到派生类)
  2. 初始化列表(从基类到派生类)
  3. 构造函数的函数体(从基类到派生类)
  4. 对象的其他操作
  5. 析构函数(从派生类到基类)

当销毁一个对象时,类中的成员函数执行顺序如下:

析构函数(从派生类到基类)

4.类组合时对象的构造顺序是怎样的?

类组合指的是在一个类中包含其他类的对象。在组合中,包含的对象是该类的成员变量,创建对象的顺序与成员变量的声明顺序相同,即先创建前面的对象,再创建后面的对象。而对象的销毁顺序与创建顺序相反,即先销毁后面的对象,再销毁前面的对象。

5.如何存储和处理字符串?

字符串可以存储在字符数组或动态分配的字符串指针中。对于字符数组,可以使用字符串函数来处理它们,例如strlen,strcpy,strcat等。对于动态分配的字符串指针,需要使用内存分配函数来分配和释放内存,例如malloc和free,并使用字符串函数来处理它们。

6.头文件<string.h>和头文件<string>有何区别?

<string.h>头文件是C语言中用于处理字符串的头文件,它包含了一系列的字符串函数,例如strlen,strcpy,strcat等。而<string>头文件是C++语言中用于处理字符串的头文件,它定义了一个名为string的类,可以使用这个类来表示和操作字符串。

7.有几种方法来表示和处理数组元素?

  • 使用一维数组:一维数组是最简单的数组类型,它由一组相同类型的元素组成,这些元素按照顺序存储在一段连续的内存空间中。

  • 使用多维数组:多维数组是一种由多个一维数组组成的数组类型,它可以表示更为复杂的数据结构,例如矩阵等。

  • 使用指针数组:指针数组是一个数组,它的每个元素都是一个指针,这些指针可以指向不同类型的数据。

  • 使用结构体数组:结构体数组是一个数组,它的每个元素都是一个结构体,结构体可以包含不同类型的数据,这种数组可以用来表示更为复杂的数据结构。

8.如何在已有的类的基础上设计新的类?

在已有的类的基础上设计新的类可以使用继承的概念,即新的类可以作为已有类的子类,继承已有类的属性和方法,并可以添加新的属性和方法,修改已有属性和方法,或者覆盖已有方法的实现。这样可以避免重复编写相似的代码,提高代码复用性和可维护性。

9.基类和派生类对象的构造顺序是怎样的?

基类和派生类对象的构造顺序是先构造基类对象,再构造派生类对象。具体来说,当创建派生类对象时,先调用基类的构造函数,再调用派生类的构造函数。当销毁派生类对象时,先调用派生类的析构函数,再调用基类的析构函数。

10.如何利用虚基类解决二义性问题?

当存在多重继承时,可能会出现二义性问题,即同名成员在不同基类中被继承,导致调用时出现歧义。可以使用虚基类来解决这个问题。虚基类是被声明为虚拟的基类,它的成员在派生类中只有一份拷贝,这样可以避免同名成员被多次继承。在派生类中通过使用虚基类语法来指定虚基类,如:

class Base {
public:
    int x;
};

class Derived1 : virtual public Base {
public:
    // ...
};

class Derived2 : virtual public Base {
public:
    // ...
};

class Derived3 : public Derived1, public Derived2 {
public:
    // ...
};

在这个例子中,Base 被声明为虚基类,Derived1Derived2 都继承自 BaseDerived3 继承自 Derived1Derived2。这样,在 Derived3 中就只有一份 Base 对象的成员

11.在继承过程中,应该注意将适当的类设置为虚基类,如果不设置为虚基类,会有什么问题?

在继承过程中,如果一个类被作为多个基类派生出来,而这些基类又有共同的基类,那么这个共同的基类就应该被声明为虚基类。这是为了避免派生类中存在多个相同的基类实例,导致多次调用同一份数据和函数,从而导致程序错误和运行效率下降。

如果不将适当的类设置为虚基类,那么每个派生类都将拥有一份基类的实例,这样会导致内存浪费和数据不一致的问题。此外,如果派生类中调用基类的成员函数时,会出现不同的实例,从而导致意外的行为发生,这种问题被称为"二义性"。因此,设置适当的虚基类是保证程序正确性的必要步骤。

12.如何将一个运算符重载为类的成员函数?

为了将运算符重载为类的成员函数,需要在类定义中创建一个成员函数,并使用运算符重载符号来命名该函数。例如,如果想要重载“+”运算符,可以将该函数命名为“operator+”。函数的参数应该是另一个与该类相同类型的对象。下面是一个重载“+”运算符的示例代码:

class MyClass {
public:
    MyClass operator+(const MyClass& other) {
        MyClass result;
        // Do some operation to calculate the sum
        return result;
    }
};

 

13.如何将一个运算符重载为类的友元函数?

为了将运算符重载为类的友元函数,需要在类定义外部创建一个友元函数,并使用运算符重载符号来命名该函数。友元函数应该具有两个参数,其中一个参数是该类的对象,另一个参数是另一个与该类相同类型的对象。下面是一个重载“+”运算符的友元函数的示例代码:

class MyClass {
private:
    int value;
public:
    MyClass(int val) : value(val) {}
    friend MyClass operator+(const MyClass& lhs, const MyClass& rhs) {
        MyClass result(lhs.value + rhs.value);
        return result;
    }
};

 

14.如何实现运行时刻的多态?

实现运行时刻的多态可以通过虚函数和动态绑定来实现。虚函数是一个在基类中声明的函数,其关键字为“virtual”,在派生类中可以被重新定义。当派生类对象通过基类指针访问该虚函数时,会根据实际的对象类型来确定要调用的函数。这个过程被称为动态绑定。

下面是一个实现运行时刻的多态的示例代码:

class Shape {
public:
    virtual void draw() {
        cout << "Drawing a shape." << endl;
    }
};

class Circle : public Shape {
public:
    void draw() {
        cout << "Drawing a circle." << endl;
    }
};

class Square : public Shape {
public:
    void draw() {
        cout << "Drawing a square." << endl;
    }
};

int main() {
    Shape* s;
    Circle c;
    Square sq;

    s = &c;
    s->draw();

    s = &sq;
    s->draw();

    return 0;
}

在这个示例代码中,定义了一个基类“Shape”和两个派生类“Circle”和“Square”,它们都重载了“draw()”函数。在主函数中,定义了一个指向基类的指针“s”,并分别将它指向“Circle”和“Square”对象。通过基类指针调用“draw()”函数时,会根据指向的对象类型来动态绑定相应的函数。这就实现了运行时刻的多态。 

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*OASIS*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值