[菜鸟求教] 一个 C++ 容器类的疑问

2015-06-24 21:50:57 +08:00
 dlllcs

这段时间在学习C++,尝试自己写了一个容器类,开始设想是模拟一个可以放下所有类型的元素的数组(就像vector那样),但是遇到了一点小问题,就像下面代码描述那样,能不能在不更改 Package 类的情况下让 Container 类能实现功能,或者这个思路本身是有问题的,如果思路有问题的话,那该怎样设计才是好的?

/*
 * main.cpp
 *
 *  Created on: Jun 16, 2015
 *      Author: dlll
 */

class Package{
    private:
        int num;

    public:
        Package(int num){
            this->num = num;
        }

        operator int(){
            return num;
        }
};

template<class T>
class Container{
    private:
        T *contents;
    public:
        Container(int size){
            contents = new T[size];
        }

        ~Container(){
            delete[] contents;
        }

        void set(int pos, T content){
            contents[pos] = contents;
        }

        T get(int pos){
            return contents[pos];
        }
};

int main(int argc, char **argv) {
    //这样写是可以的
    Container<int> intContainer(10);

    /*
     * 这样写是不行的,会报错:
     * ../main.cpp:32:13: error: no matching function for call to ‘Package::Package()’
         contents = new T[size];
     * */
    Container<Package> packageContainer(10);

    /*
     * 问题: 能不能在不更改 Package 类的情况下让 Container 类能实现功能
     */
}
1242 次点击
所在节点    C
6 条回复
njustyw
2015-06-24 22:22:11 +08:00
package没有默认构造函数
ini
2015-06-24 22:43:42 +08:00
vector也要看情况:

```
vector<Package> vec;
```

这种情况是不需要的,因为这时候vector还不会调构造函数。
ini
2015-06-24 22:48:39 +08:00
你的 Container 如果要正常工作的话,不要用 new T[size] 来申请内存,这会导致默认构造函数的调用;可以用 malloc 来申请足够的内存,然后再在需要的时候用 placement new 来调用 Package 的构造函数。
dlllcs
2015-06-25 13:41:44 +08:00
@ini 万分感谢哦,经过您的指点,我改成下面这样子完美通过编译和运行,大神看下还有哪里需要改动或者优化不 嘿嘿

```c++
#include <cstdlib>
#include <iostream>

class Package{
private:
int num;

public:
Package() = delete;

Package(int num){
std::cout << "create Package " << num << std::endl;
this->num = num;
}

Package(Package& o){
std::cout << "copy Package " << o.num << std::endl;
num = o.num;
}


virtual ~Package(){
std::cout << "delete Package " << num << std::endl;
}


virtual operator int(){
return num;
}
};

class Package2 : public Package{
private:
int num2;

public:
Package2() = delete;

Package2(int num):Package(-1){
std::cout << "create Package2 " << num << std::endl;
this->num2 = num;
}

Package2(Package2& o):Package(-1){
std::cout << "copy Package2 " << o.num2 << std::endl;
num2 = o.num2;
}


virtual ~Package2(){
std::cout << "delete Package2 " << num2 << std::endl;
}


virtual operator int(){
return num2;
}
};

template<class T>
class Container{
private:
struct contentContainer{
T content;
bool isUse;
};

contentContainer *contents;
int size;
public:
Container(int size){
contents = (contentContainer *)::malloc(sizeof(contentContainer) * size);
for(int i = 0; i < size; ++i)
contents[i].isUse = false;
this->size = size;
}

~Container(){
for(int i = 0; i < size; ++i){
auto &con = contents[i];
if (con.isUse){
con.content.~T();
}
}
free(contents);
}

void set(int pos, T content){
auto &con = contents[pos];
if (con.isUse){
con.content = content;
}else{
new(&con.content) T(content);
con.isUse = true;
}
}

T& get(int pos){
return contents[pos].content;
}
};

int main(int argc, char **argv) {
// 测试 Package 和 Package2 的大小
std::cout << "sizeof(Package): " << sizeof(Package) << std::endl;
std::cout << "sizeof(Package2): " << sizeof(Package2) << std::endl << std::endl;

Container<int> intContainer(10);

Container<Package> packageContainer(10);
packageContainer.set(1, Package(100));
std::cout << packageContainer.get(1) << std::endl;
}
```
ini
2015-06-25 23:30:35 +08:00
@dlllcs 不要称呼我为“您”或者“大神”,承受不起。。

你这个作为例子应该差不多了,但从工程角度,应该还有改进的地方:

1. 只有一个参数的构造函数最好声明为explicit
2. 不要随便定义转义操作符
3. 另外,一个类的拷贝构造函数、赋值操作符、析构函数一般是要没有就没有,要有三个都要同时有的(简称rule of three),你这里没有实现完全。

一家之言,见笑了。
dlllcs
2015-06-26 13:33:27 +08:00
@ini 承你所言,那我就冒昧称呼为你好了,嘿嘿

你这三个见解确实了结了我对输出结果的疑惑,原来是发生了隐式转换,谢谢啦!以后我会注意的!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/200929

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX