C++中使用构造函数和析构函数的对象计数器
Object counter in C++ using Constructor and Destructor
所以,我是新来的,如果我犯了任何错误,请耐心等待。
我是一名学习C++的大学生,刚接触构造函数和析构函数。
我想做的是:我需要创建一个程序来维护对象的实时计数,即无论何时创建或销毁该类的对象,对象计数器都会分别递增/递减并显示(这是我的逻辑,建议会让我很感激)。
这意味着要创建一个静态变量,我想出了这个:
class objectCount
{
protected:
static int count;
public:
objectCount()
{
count++;
cout<<"Object of type class created. nNo. of objects of type class currently: "<<count<<endl;
}
~objectCount()
{
count--;
cout<<"Latest object of type class deleted. nNo. of objects of type class currently: "<<count<<endl;
}
};
int objectCount::count=0;
void main()
{
int ch;
clrscr();
cout<<"--------------- || OBJECT COUNTER || ----------------"<<endl;
do {
cout<<"1. Create Objectn2. Delete Objectn3.Exit";
cout<<endl<<"Enter your choice: ";
cin>>ch;
switch(ch)
{
case 1: objectCount();
break;
case 2: ~objectCount();
break;
case 3: break;
default: cout<<endl<<"Invalid Choice.";
break;
};
}while(ch!=3);
getch();
}
所以,我以为我已经做好了准备,但后来TurboC(是的,我的大学强迫我们使用TC,因此我别无选择,只能使用它)在"案例2:~objectCounter();"部分给了我一个错误(非法结构操作)。我翻阅了这些书,意识到我忘记了构造函数也需要对象声明。(objectCount OC;)
但现在我很困惑,究竟该如何更改代码才能使其工作。
我需要它,以便根据用户的选择,创建一个对象,更新和打印对象数量,删除其他对象,打印和更新对象数量,完成后退出。
我四处搜索,但通常发布示例的人只是声明有限数量的对象,如"objectCount c1;objectCount c2;",然后就这样做了,但我的情况并非如此。
尊敬的、善良的、温和的、知识渊博的社区,你们中的任何人能帮助我吗?
编辑:理想输出:
--------------- || OBJECT COUNTER || ----------------
1. Create Object
2. Delete Object
3. Exit
Enter your choice: 1
Object of type class created.
No. of objects of type class currently: 1 //Static variable incremented & displayed here.
1. Create Object
2. Delete Object
3. Exit
Enter your choice: 1
Object of type class created.
No. of objects of type class currently: 2 //Static variable incremented & displayed here.
1. Create Object
2. Delete Object
3. Exit
Enter your choice: 2
Object of type class deleted
No. of objects of type class currently: 1 //Static variable decremented & displayed here.
1. Create Object
2. Delete Object
3. Exit
Enter your choice: 3
编辑2:我想我只会按照besc的建议使用一个由100个对象组成的数组,现在应该可以了。
但感谢大家的回答,是的,我一定会超越TC,学习真正的交易。
计数逻辑的实现是正确的(只要您停留在单线程场景中),但main()
不是。
在case 1
的开关中,您正在做的是创建一个未命名的临时objectCount
对象,该对象将立即再次被销毁。您将看到ctor被立即调用,然后是对dtor的调用。为什么它会立即被摧毁?因为你没有给它起名字。所以,这不是特别有用,但有效;尽管这显然不是你想要的。
case 2
不会编译,因为您调用的dtor没有对象。实际上这里有两个问题。
(1)dtor需要知道应该销毁哪个objectCount
对象。在这方面,它的作用类似于任何其他非静态成员函数。这将起作用:
// Creates an object, ctor gets called.
objectCount obj;
// Calls the destructor on obj.
// DO NOT DO THIS! See (2).
obj.~objectCount();
(2)在C++中,只有极少数情况下显式调用dtor。只要你处于学习C++的早期阶段,它们就不相关。因此,这是一条有效的规则:如果你明确地调用dtor,你就做错了。当一个对象死亡时,Dtor被隐含地调用。死亡是如何发生的取决于你的对象被分配到哪里。
堆栈上:
void func() {
objectCount obj;
} // obj goes out of scope here: dtor is called
堆上:
objectCount* obj = new objectCount;
// ...
delete obj; // dtor is called
只要有可能,就更喜欢堆栈,因为使用new/delete进行手动内存管理极易出错。
正如您在堆栈示例中看到的,范围是由大括号定义的。如果您需要对对象的生存期进行更细粒度的控制,可以使用一组"独立"curlies。也就是说,你的main()
可能是这样的:
//...
do {
cout << "1. Create/destroy on the stackn"
cout << "2. Create/destroy on the heapn
cout << "3.Exit";
cout<<endl<<"Enter your choice: ";
cin>>ch;
switch(ch)
{
case 1: {
{
// Note the standalone set of curlies.
objectCount obj;
}
break;
}
case 2: {
objectCount* obj = new objectCount;
delete obj;
break;
}
case 3: break;
default: cout<<endl<<"Invalid Choice.";
break;
};
}while(ch!=3);
// ...
若要保留要显式创建和销毁的用户选择,您需要在此处使用new/delete。没有合适的范围可以提供相同的效果。但在你这么做之前,先想想可能出错的地方。例如,如果用户决定连续创建两次,会发生什么。。。或者连续删除两次。
编辑:
要让用户创建和销毁任意数量的对象,您需要保留一个包含现有对象的列表,也称为std::vector
。在这一点上,TurboC成为了一个真正的问题,因为它早于C++标准模板库(STL),矢量是STL的一部分。在这一点上,您不希望自己实现向量。
让我说一下,你们州教育委员会的决定是多么令人难以置信地愚蠢,迫使你们使用DOS时代的IDE。那样你就不会学到任何有用的C++。如果你做C++只是为了获得学分,那么就把它忘掉吧。但如果你对这种语言感兴趣,那就给自己找一个现代编译器和IDE,在自己的时间里做一些真正的C++。你选择什么并不重要:免费版的Visual Studio、Clang或GCC与Qt Creator、Eclipse、CLion:任何东西都将在与TurboC完全不同的宇宙中播放。[叹气现在感觉好多了,这是我的心里话;)。]
好的,如何解决眼前的问题?让它更简单。使用C样式的固定长度数组,该数组包含指向已创建对象的指针和保存当前已分配对象数的变量。
// ... in main() outside the loop ...
// 100 objects should be enough for everybody :)
// DO NOT DO THIS IN REAL C++! Use std::vector instead!
objectCount* object_ptrs[100];
int current_max_idx = 0;
现在,您可以使用new
/delete
创建和销毁多达100个对象,同时递增和递减current_max_idx
。当程序退出时,请确保delete
是所有剩余的对象,并记住数组是从零开始的,即object_ptrs
的索引为0到99。
还要考虑从ctor和dtor中删除计数逻辑。它是多余的,因为current_max_idx
变量执行相同的工作,并且在switch
中可以在创建/销毁时进行打印。
欢迎!
~objectCount()
的问题本质上是它说"删除objectCount对象"。。。编译器会说"哪一个?"如果你不以某种方式跟踪你创建的对象,你可能会泄露这些对象的内存。
我建议使用new
和delete
关键字,而不是直接调用构造函数和析构函数。这些操作在objectCount指针上,因此例如,您可以有以下代码:
objectCount * my_object = new objectCount(); // allocates memory, calls constructor
delete my_object; // calls destructor, frees memory
这就是如何对单个objectCount对象进行内存管理。为了保留其中的许多对象,您可能需要维护这些指针的数组或std::vector
。
- 什么时候调用组成单元对象的析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- C++析构函数调用两次,堆栈分配的复合对象
- 如何从 Gtk::窗口调用派生对象的析构函数
- 为什么数组中对象的析构函数在被另一个对象替换时不被调用?
- 为什么为未删除的对象调用析构函数?
- 对象的构造函数和析构函数
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- C++使用函数对象的线程,如何调用多个析构函数而不是构造函数?
- 从未调用shared_ptr对象的析构函数
- 是否可以在其析构函数中使用指向已销毁对象的指针?
- 使用私有析构函数删除动态分配的对象
- C++ std::线程调用方法,从对象原因到调用此类的析构函数
- 当我使用dynamic_cast并删除对象删除时,析构函数是如何工作的?
- C++ - 析构函数只是释放内存还是实际删除对象
- 受保护的析构函数禁用在堆栈上创建派生类的对象?
- 当 T 具有非平凡析构函数时,类类型 T 的对象是否可以常量初始化?
- 编译器是否在由 new 初始化的对象上调用隐式析构函数
- 受保护析构函数对象在堆vs堆栈上的分配