9.4学习记录新

一.先构造成员
再构造自身(调用构造函数)

1.代码如下

// 引入C++标准库中的输入输出流库  
#include <iostream>  
  
// 使用命名空间std,这样可以使用std中的符号,而不必在每个符号前都加上std::  
using namespace std;  
  
// 下面定义了三个类A、B和C  
  
/*  
先构造成员  
再构造自身(调用构造函数)  
*/  
  
// 定义类A  
class A {  
public:  
  // A的默认构造函数,输出"Constructing A"  
  A() { cout << "Constructing A" << endl; }  
    
  // A的析构函数,输出"Destructing A"  
  ~A() { cout << "Destructing A" << endl; }  
};  
  
// 定义类B  
class B {  
public:  
  // B的默认构造函数,输出"Constructing B"  
  B() { cout << "Constructing B" << endl; }  
    
  // B的析构函数,输出"Destructing B"  
  ~B() { cout << "Destructing B" << endl; }  
};  
  
// 定义类C  
class C {  
public:  
  // C的默认构造函数,输出"Constructing C"  
  C() { cout << "Constructing C" << endl; }  
    
  // C的析构函数,输出"Destructing C"  
  ~C() { cout << "Destructing C" << endl; }  
    
  // 类C中包含类B的实例b和类A的实例a,这是类的成员对象,它们会在C对象创建时自动创建,在C对象销毁时自动销毁  
  B b;  
  A a;  
};  
  
// 定义主函数,程序的执行从这里开始  
int main() {  
  // 创建一个C类的实例c  
  C c;  
    
} // main 函数结束,程序结束,此时会按照构造函数的调用顺序,首先析构c中的A实例a,然后析构B实例b,最后析构C实例c。
  • 构造函数:当创建一个C的实例时,会打印出"Constructing C"。注意,在C的构造函数中,首先创建了类B的实例(即b),然后创建了类A的实例(即a)。这是因为C中先声明了B的成员变量b,后声明了A的成员变量a。因此,在构造C的时候,会先构造b,再构造a。
  • 析构函数:当C的实例被销毁时,会首先销毁A的实例(即a),然后销毁B的实例(即b),最后打印出"Destructing C"。这是因为在C的析构函数中,析构的顺序与构造的顺序相反。

2.析构函数

析构函数是C++类的一个特殊成员函数,它在一个对象的生命周期结束时自动调用。析构函数的名字由一个波浪号接类名构成,形如~ClassName()。析构函数主要用于进行对象的清理工作,例如释放动态分配的内存、关闭打开的文件等。

析构函数的一个重要特点是它不能带有任何参数,也不能返回任何值。另外,一个类只能有一个析构函数,而且析构函数不能被用户直接调用,它是由编译器在对象销毁时自动调用的。

当一个对象离开其作用域或者显式地调用delete操作符时,析构函数会被自动调用。因此,析构函数常常用于资源的清理工作,以确保资源的正确释放。

以下是一个简单的析构函数示例:

class MyClass {  
public:  
    ~MyClass() {  
        // 清理资源的代码  
    }  
};

在这个例子中,当MyClass对象被销毁时,析构函数将被自动调用,执行其中的清理代码。

二.基类

1.基类(或称父类)是在C++中,当一个类被其他类继承时,被继承的类就是基类。基类定义了所有派生类的公有属性,派生类继承了这些属性,并且增加了自己特有的属性。基类是派生类的父类,可以拥有成员变量和成员函数。

2.代码示例

// 引入C++标准库中的输入输出流库  
#include <iostream>  
  
// 使用命名空间std,这样可以使用std中的符号,而不必在每个符号前都加上std::  
using namespace std;  
  
// 定义一个名为Base的类,该类是所有其他类的基类  
class Base {  
private:  
  // 定义一个私有成员变量x,该变量只能被Base类的成员函数访问  
  int x;  
  
public:  
  // 定义一个公共构造函数,该函数用于初始化x并输出一条消息  
  Base(int a) {  
    x = a;  
    cout << "Base constructor x=" << x << endl;  
  }  
    
  // 定义一个析构函数,该函数在Base对象被销毁时调用并输出一条消息  
  ~Base() { cout << "Base destructor..." << endl; }  
};  
  
// 定义一个名为Derived的类,该类从Base类派生而来  
class Derived : public Base {  
private:  
  // 定义一个私有成员变量y,该变量只能被Derived类的成员函数访问  
  int y;  
  
public:  
  // 定义一个公共构造函数,该函数用于初始化y、调用基类的构造函数并输出一条消息  
  Derived(int a, int b) : Base(a) { //派生类构造函数的初始化列表  
    y = b;  
    cout << "Derived constructor y=" << y << endl;  
  }  
    
  // 定义一个析构函数,该函数在Derived对象被销毁时调用并输出一条消息  
  ~Derived() { cout << "Derived destructor..." << endl; }  
};  
  
// 定义主函数,程序的执行从这里开始  
int main() {  
  // 创建一个Derived类的实例d,该实例使用参数(1,2)调用其构造函数  
  Derived d(1, 2);  
    
  // 主函数返回0,表示程序正常结束  
  return 0;  
}

 当此程序执行时,它会首先创建Base类的实例,然后创建Derived类的实例。创建Base类实例时,会输出"Base constructor x=1"。创建Derived类实例时,会首先调用Base类的构造函数,输出"Base constructor x=1",然后初始化Derived类的y变量并输出"Derived constructor y=2"。当主函数结束时,会销毁Derived类的实例并输出"Derived destructor...",然后销毁Base类的实例并输出"Base destructor..."。

3.基类和构造函数的联合使用

代码如下

// 引入C++标准库中的输入输出流库  
#include <iostream>  
  
// 使用命名空间std,这样可以使用std中的符号,而不必在每个符号前都加上std::  
using namespace std;  
  
// 定义一个名为A的类,该类是所有其他类的基类  
class A {  
public:  
  // A的默认构造函数,输出"Constructing A"并换行  
  A() { cout << "Constructing A" << endl; }  
    
  // A的析构函数,输出"Destructing A"并换行  
  ~A() { cout << "Destructing A" << endl; }  
};  
  
// 定义一个名为B的类,该类是所有其他类的基类  
class B {  
public:  
  // B的默认构造函数,输出"Constructing B"并换行  
  B() { cout << "Constructing B" << endl; }  
    
  // B的析构函数,输出"Destructing B"并换行  
  ~B() { cout << "Destructing B" << endl; }  
};  
  
// 定义一个名为C的类,该类是所有其他类的基类  
class C {  
public:  
  // C的默认构造函数,输出"Constructing C"并换行  
  C() { cout << "Constructing C" << endl; }  
    
  // C的析构函数,输出"Destructing C"并换行  
  ~C() { cout << "Destructing C" << endl; }  
};  
  
// 定义一个名为D的类,该类从C类派生而来,包含A、B和C类的实例成员  
class D : public C {  
public:  
  // D的默认构造函数,输出"Constructing D"并换行  
  D() { cout << "Constructing D" << endl; }  
    
  // D的析构函数,输出"Destructing D"并换行  
  ~D() { cout << "Destructing D" << endl; }  
    
  // 在D类中定义B类的实例b和A类的实例a以及C类的实例c  
  B b;  
  A a;  
  C c;  
};  
  
// 定义主函数,程序的执行从这里开始  
int main() {  
  // 创建一个D类的实例d,该实例使用默认构造函数进行初始化,并输出相应的消息  
  D d;  
    
  // 主函数返回0,表示程序正常结束  
  return 0;  
}

当此程序执行时,它会首先创建C类的实例(因为D类是从C类派生而来的)。当主函数结束时,会销毁D类的实例并输出相应的消息,然后销毁C类的实例并输出相应的消息。

输出结果为:Constructing C
Constructing B
Constructing A
Constructing C
Constructing D
Destructing D
Destructing C
Destructing A
Destructing B
Destructing C

再看一个代码

#include <iostream>
using namespace std;
class A {
public:
	A() { cout << "Constructing A" << endl; }
	~A() { cout << "Destructing A" << endl; }
};
class B : public A {
public:
	~B() { cout << "Destructing B" << endl; }
};
int main() {
	B b;

}

输出结果为:Constructing A
Destructing B
Destructing A

4.c++类中protect和private的区别

在C++中,privateprotected是两种访问修饰符,它们决定了类成员的访问权限。

  1. private:这是默认的访问修饰符。当一个成员被声明为private时,它只能在类的内部被访问,包括在该类的成员函数和友元函数中。在类的外部,包括在其他类的成员函数中,都不能直接访问private成员。
  2. protected:当一个成员被声明为protected时,它可以在类的内部和其派生类中被访问。换句话说,protected成员在类内部和派生类中的访问权限与private成员相同,但是在类外部不能直接访问。然而,如果一个类是从protected的基类派生的,那么该类的成员函数可以访问基类的protectedpublic成员。

总的来说,主要的区别在于,protected成员可以在派生类中被访问,而private成员则不能。这两种访问修饰符都是为了实现封装和信息隐藏,以保护数据和避免不必要的访问和修改。

5.基类和构造函数的联合使用新

#include <iostream> // 引入iostream库,这个库提供了输入和输出的功能。  
using namespace std; // 使用命名空间std,这样就可以直接使用std中的所有名字,而不需要在每个名字前都写std::。  
  
// 定义类A,有一个私有成员变量x。  
class A {  
  int x;  
  
public:  
  // 定义构造函数,接收一个整数参数i,默认值为0。在对象创建时,如果没有提供参数,就会使用这个默认值。  
  A(int i = 0) {  
    x = i; // 将传入的参数i赋值给成员变量x。  
    // 输出当前对象的信息。  
    cout << "A-----" << x << endl;  
  }  
};  
  
// 定义类B,有一个私有成员变量y。  
class B {  
  int y;  
  
public:  
  // 定义构造函数,接收一个整数参数。  
  B(int i) {  
    y = i; // 将传入的参数i赋值给成员变量y。  
    // 输出当前对象的信息。  
    cout << "B-----" << y << endl;  
  }  
};  
  
// 定义类C,有一个私有成员变量z。  
class C {  
  int z;  
  
public:  
  // 定义构造函数,接收一个整数参数。  
  C(int i) {  
    z = i; // 将传入的参数i赋值给成员变量z。  
    // 输出当前对象的信息。  
    cout << "C-----" << z << endl;  
  }  
};  
  
// 定义类D,从类B公有继承,并含有三个类C和A的成员变量。  
class D : public B {  
public:  
  C c1, c2; // 两个C类的实例作为D类的成员。  
  A *a1 = new A(10); // 一个指向A类实例的指针a1,动态分配在堆上,初始化为一个新创建的A类实例,参数为10。  
  A a0, a4; // 两个A类的实例作为D类的成员。  
  // D类的构造函数,初始化其成员变量。  
  D() : a4(4), c2(2), c1(1), B(1) { cout << "D-----5" << endl; }  
};  
  
// 主函数,程序的入口。  
int main() {  
  // 创建一个D类的实例d。  
  D d;  
  return 0; // 返回0,表示程序正常结束。  
}

B-----1
C-----1
C-----2
A-----10
A-----0
A-----4
D-----5

这表示按照构造函数的调用顺序,先构造基类(B),然后是派生类D和其成员变量c1、c2、a1、a0、a4。最后才是D。

在面向对象编程中,一个类可以访问其他类的成员变量和方法,只要它们满足以下条件:

  1. 访问修饰符:访问修饰符决定了类和成员的可见性。如果一个类的方法使用了public或默认访问修饰符,那么它就可以被其他类访问。如果使用了private访问修饰符,则只能在当前类中被访问。
  2. 继承:如果一个类继承了另一个类,那么它就可以访问父类的成员变量和方法。通过继承,子类可以重写父类的方法,也可以添加新的成员变量和方法。
  3. 友元类:在某些编程语言中,可以使用友元类来允许一个类访问另一个类的私有成员。友元类是一种特殊的声明,允许一个类在另一个类内部访问其私有成员。

根据这些条件,如果D类可以调用A和C类的成员变量和方法,那么它们必须满足以下条件之一:

  1. A和C类的成员变量和方法使用了public或默认访问修饰符,并且没有使用private修饰符。
  2. D类继承了A或C类。
  3. A和C类声明了D类为友元类,允许D类访问它们的私有成员。

需要注意的是,如果A和C类使用了private访问修饰符,那么它们的方法和成员变量只能在它们所在的类中被访问,无法被其他类访问。如果使用了默认访问修饰符(在Java中为default),则只能在同一个包中的其他类中访问。如果使用了protected访问修饰符,则可以在同一个包中的其他类以及所有子类中访问。

因此,如果D可以调用A和C的成员变量和方法,那么这些成员变量和方法必须满足以上条件之一。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值