V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dlllcs
V2EX  ›  C

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

  •  
  •   dlllcs · 2015-06-24 21:50:57 +08:00 · 1074 次点击
    这是一个创建于 3226 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这段时间在学习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 类能实现功能
         */
    }
    
    第 1 条附言  ·  2015-06-24 22:26:01 +08:00
    package没有默认构造函数这个我有知道,但是测试中 vector 就可以装下没有默认构造函数的package,这是为什么呢?
    6 条回复    2015-06-26 13:33:27 +08:00
    njustyw
        1
    njustyw  
       2015-06-24 22:22:11 +08:00 via Android   ❤️ 1
    package没有默认构造函数
    ini
        2
    ini  
       2015-06-24 22:43:42 +08:00
    vector也要看情况:

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

    这种情况是不需要的,因为这时候vector还不会调构造函数。
    ini
        3
    ini  
       2015-06-24 22:48:39 +08:00
    你的 Container 如果要正常工作的话,不要用 new T[size] 来申请内存,这会导致默认构造函数的调用;可以用 malloc 来申请足够的内存,然后再在需要的时候用 placement new 来调用 Package 的构造函数。
    dlllcs
        4
    dlllcs  
    OP
       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
        5
    ini  
       2015-06-25 23:30:35 +08:00   ❤️ 1
    @dlllcs 不要称呼我为“您”或者“大神”,承受不起。。

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

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

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

    你这三个见解确实了结了我对输出结果的疑惑,原来是发生了隐式转换,谢谢啦!以后我会注意的!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1396 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:33 · PVG 01:33 · LAX 10:33 · JFK 13:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.