#include
using namespace std;class T {
public:~T() { cout << "Destroying..." << i << endl; }void Setij(int a, int b) { i = a, j = b; }int GetMuti() { return i * j; }
protected:int i, j;
};
int main()
{T* p = new T[5];for (int j = 0; j < 5; ++j) p[j].Setij(j, j);for (int k = 0; k < 5; ++k) cout << "Multi[" << k << "] is:" << p[k].GetMuti() << endl;//程序结束并不会隐式地调用析构函数,需要显式调用析构函数//析构顺序与构造顺序相反delete[]p;return 0;
}
#include
using namespace std;class Vector {
public:Vector(int s = 100);~Vector();int& Elem(int idx);void Display();void Set();
protected:int size;int* buffer;
};Vector::Vector(int s)
{buffer = new int[size = s]; //巧妙1: 初始化size的同时也初始化了buffer
}
Vector::~Vector()
{cout << "扫尾工作..." << endl;delete []buffer;
}int& Vector::Elem(int idx)
{if (idx < 0 || idx >= size){cout << "error in index" << endl;exit(-1);}return buffer[idx];
}void Vector::Display()
{for (int i = 0; i < size; ++i)cout << Elem(i) << endl;
}void Vector::Set()
{for (int i = 0; i < size; ++i)Elem(i) = i + 1; //巧妙2: 利用返回值为引用,直接修改了buffer(i)
}int main()
{ Vector a(10);Vector b(a);a.Set();b.Display();return 0;
}
可以很清楚看到浅拷贝所造成的错误:在析构的时候会重复析构,这是由于浅拷贝时,b的buffer指针和a的buffer指针指向的是同一片空间
如何更改?
换为深拷贝!
即弃用默认拷贝构造函数,自己写一个拷贝构造函数
#include
using namespace std;class Vector {
public:Vector(int s = 100);Vector(const Vector& v); //拷贝构造函数~Vector();int& Elem(int idx);void Display();void Set();
protected:int size;int* buffer;
};Vector::Vector(int s)
{buffer = new int[size = s]; //巧妙1: 初始化size的同时也初始化了buffer
}
Vector::Vector(const Vector& v)
{//照猫画虎 重新开辟空间,使得通过调用拷贝构造函数创建的对象的buffer指向另一片空间this->buffer = new int[this->size = v.size];//拷贝数据 [也可不加this指针进行访问]for (int i = 0; i < size; ++i)buffer[i] = v.buffer[i];
}
Vector::~Vector()
{cout << "扫尾工作..." << endl;delete []buffer;
}int& Vector::Elem(int idx)
{if (idx < 0 || idx >= size){cout << "error in index" << endl;exit(-1);}return buffer[idx];
}void Vector::Display()
{for (int i = 0; i < size; ++i)cout << Elem(i) << endl;
}void Vector::Set()
{for (int i = 0; i < size; ++i)Elem(i) = i + 1; //巧妙2: 利用返回值为引用,直接修改了buffer(i)
}int main()
{ Vector a(10);Vector b(a);a.Set();b.Display();return 0;
}
改为深拷贝后,a、b对象不会相互影响,由于b未调用set()函数,所以其buffer里面的数据仍为随机值
#include
using namespace std;
int main()
{int* p1 = new int(5); //只分配一个int类型的空间,并初始化为5cout << *p1 <<" "<< p1[0] << endl;delete p1;int* p2 = new int[5]; // 指向数组p2[0] = 1;p2[1] = 10;cout << *p2 << " " << p2[0] << " " << p2[1] << endl;delete[] p2; //依次销毁p2所指向的完整完整空间return 0;
}
delete []p 是指 释放p所指向的完整空间
记清楚两者的适用条件即可
常数据成员名只可在初始化列表中进行
(上机在VS2019尝试后,发现在定义时初始化也能编译通过,但并不建议这样做)
默认构造函数(default constructor)就是在没有显式提供初始化式时调用的构造函数。
它由不带参数的构造函数,或者为所有的形参提供默认实参的构造函数定义
①
class T{
public:T(){}
protected:int x;
}②
class T{
public:T(int xx = 0) {}
protected:int x;
}
B
cin 属于 istream类
cout 属于 ostream类
A
类模板不可以重载,但是函数模板可以重载。
静态数据成员指的是 static修饰的数据成员
A
A
多态分为4类: 重载多态 、 强制多态、参数多态、包含多态
前两种又被称为专用多态
后两种又被称为通用多态
前三种的绑定工作在编译连接阶段即可完成
包含多态的绑定工作在程序运行阶段才可完成
B
多态分为静态多态(编译时多态、静态联编、早绑定)和动态多态(运行时多态、动态联编、晚绑定)
正确
❌
static修饰的数据成员为该类的所有对象_共享___
#include
using namespace std;class Complex {
public:Complex(double rr = 0.0 ,double ii = 0.0):r(rr),i(ii){}void show() { cout << r << " " << i << endl; }Complex operator+(const Complex& c) {return Complex(this->r + c.r, this->i + c.i);}
private:double r, i;
};int main()
{Complex c1(-1, 4), c2(2, 5);c1.show();c2.show();Complex c3 = c1 + c2;c3.show();return 0;
}
B
#include
using namespace std;class T {
public:static void show_x() { return this->x; } //错误,this指针只存在于非静态函数内部
private:static int x;
};int T::x = 1; //静态数据成员类外初始化int main()
{return 0;
}
#include
using namespace std;
#include const double PI = acos(-1);class CShape {
public:virtual double GetLength() const = 0;
};class CSqure :public CShape {
public:CSqure(double x, double y):x(x),y(y){}double GetLength()const { return 2 * (x + y); }
private:double x, y;
};class CCircle :public CShape {
public:CCircle(double r):r(r){}double GetLength()const { return 2 * PI * r; }
private:double r;
};int main()
{CSqure c1(1, 2);cout << c1.GetLength() << endl;CCircle c2(1);cout << c2.GetLength() << endl;return 0;
}
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
#include
using namespace std;class B {
public:B(){}B(int i) { b = i; }virtual void virfun(){cout << "B::virfun() called.\n";}
private:int b;
};class D :public B {
public:D(){}D(int i, int j) :B(i) { d = j; }
private:int d;void virfun(){cout << "D::virfun() called.\n";}
};void fun(B* obj)
{obj->virfun();
}int main()
{D* pd = new D;fun(pd);return 0;
}
虽然在子类中声明了private,但其实仍然可以调用虚函数
虚函数编译时的访问权限仅仅是和调用者(指针、引用)的类型有关,编译器只要知道这个类型有一个可以访问的虚函数就行了,并不查看具体对象类型中该虚函数的访问权限
简而言之,基类是public权限即可成功调用虚函数
A
友元关系破坏了封装性,可提高程序的运行效率
C
只可访问公有成员
面向对象将数据和对数据的操作作为一个相互依赖,不可分割的整体,采用了数据抽象和信息隐蔽技术。
抽象性、封装性、继承性和多态性
在C++中,函数的定义不可以嵌套,类的定义可以嵌套。
2022.11.19 整理
欢迎交流、讨论、指正~
不正确、不理解之处欢迎评论留言~