一.先构造成员
再构造自身(调用构造函数)
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++中,private
和protected
是两种访问修饰符,它们决定了类成员的访问权限。
private
:这是默认的访问修饰符。当一个成员被声明为private
时,它只能在类的内部被访问,包括在该类的成员函数和友元函数中。在类的外部,包括在其他类的成员函数中,都不能直接访问private
成员。protected
:当一个成员被声明为protected
时,它可以在类的内部和其派生类中被访问。换句话说,protected
成员在类内部和派生类中的访问权限与private
成员相同,但是在类外部不能直接访问。然而,如果一个类是从protected
的基类派生的,那么该类的成员函数可以访问基类的protected
和public
成员。
总的来说,主要的区别在于,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。
在面向对象编程中,一个类可以访问其他类的成员变量和方法,只要它们满足以下条件:
- 访问修饰符:访问修饰符决定了类和成员的可见性。如果一个类的方法使用了public或默认访问修饰符,那么它就可以被其他类访问。如果使用了private访问修饰符,则只能在当前类中被访问。
- 继承:如果一个类继承了另一个类,那么它就可以访问父类的成员变量和方法。通过继承,子类可以重写父类的方法,也可以添加新的成员变量和方法。
- 友元类:在某些编程语言中,可以使用友元类来允许一个类访问另一个类的私有成员。友元类是一种特殊的声明,允许一个类在另一个类内部访问其私有成员。
根据这些条件,如果D类可以调用A和C类的成员变量和方法,那么它们必须满足以下条件之一:
- A和C类的成员变量和方法使用了public或默认访问修饰符,并且没有使用private修饰符。
- D类继承了A或C类。
- A和C类声明了D类为友元类,允许D类访问它们的私有成员。
需要注意的是,如果A和C类使用了private访问修饰符,那么它们的方法和成员变量只能在它们所在的类中被访问,无法被其他类访问。如果使用了默认访问修饰符(在Java中为default),则只能在同一个包中的其他类中访问。如果使用了protected访问修饰符,则可以在同一个包中的其他类以及所有子类中访问。
因此,如果D可以调用A和C的成员变量和方法,那么这些成员变量和方法必须满足以上条件之一。