2012-01-04 49 views
2

我在這裏是全新的,所以我對這裏的寫作風格不是很熟悉,所以如果問題看起來不像應該那麼抱歉。 我的問題是,我如何創建一個對象數組,但不是默認的構造函數? 如果我有這樣的事情:如何在創建對象數組時避免默認的構造函數?

set<movie> a(3); 
set<movie> b(2); 

和構造: 對於電影

movie::movie() 
{ 
    this->naziv=0; 
    this->reditelj=0; 
    this->trajanje=0; 
} 

movie::movie(char *name, char *red, int len) 
{ 
    this->naziv=new char[strlen(name)+1]; 
    strcpy(naziv,name); 
    this->reditelj=new char[strlen(red)+1]; 
    strcpy(reditelj,red); 
    this->trajanje=len; 
} 

而對於集:

template<class t> 
set<t>::set() 
{ 
    this->br=0; 
    this->niz=0; 
} 

set<t>::set(int b) 
{ 
    this->br=b; 
    this->niz=new t[br]; 
} 

答案是偉大的,但當然,他們教給我們一些關於C++的基本知識,如何創建類,模板類,我的意思是,從一開始就編寫程序,所以現在我們不使用那些大多數喲你提到。這個任務就是用這種方式編寫代碼,那我該怎麼做呢? 這個任務是做一個類和一個模板類,模板類實際上是一個對象數組,所以我應該創建一個對象,這是一個對象數組和其他一些函數。

這裏是我的全部代碼:

Set.h

#pragma once 
#include<iostream> 
using namespace std; 

template<class t> 
class set 
{ 
    int br; 
    t* niz; 
public: 
    set(); 
    set(int b); 
    ~set(); 
    set(set& copy); 
    int vrati_br_elem() 
    { 
     return br; 
    } 
    bool pripada(t elem); 
    set operator*(set& drugi); 
    friend istream& operator>> <>(istream& ulaz,set<t> &s); 
    friend ostream& operator<< <>(ostream& izlaz,set<t> &s); 
}; 

template<class t> 
set<t>::set() 
{ 
    this->br=0; 
    this->niz=0; 
} 

template<class t> 
set<t>::set(int b) 
{ 
    this->br=b; 
    this->niz=new t[br]; 
} 

template<class t> 
set<t>::~set() 
{ 
    if(this->niz!=0) 
     delete [] niz; 
} 

template<class t> 
bool set<t>::pripada(t elem) 
{ 
    for(int i=0;i<this->br;i++) 
     if(this->niz[i]=elem) 
      return true; 
    return false; 
} 

template<class t> 
set<t> set<t>::operator *(set<t> &drugi) 
{ 
    int broj=0; 
    set<t> pom((this->br>drugi.br)?this->br:drugi.br); 
    for(int i=0;i<this->br;i++) 
     for(int j=0;j<drugi.br;j++) 
      if(this->niz[i]==drugi.niz[j]) 
       pom.niz[broj++]=this->niz[i]; 
    pom.br=broj; 
    return pom; 
} 

template<class t> 
istream& operator>>(istream& ulaz,set<t> &s) 
{ 
    for(int i=0;i<s.br;i++) 
     cin>>s.niz[i]; 
    return ulaz; 
} 

template<class t> 
ostream& operator<<(ostream& izlaz,set<t> &s) 
{ 
    for(int i=0;i<s.br;i++) 
     cout<<endl<<s.niz[i]<<endl; 
    return izlaz; 
} 

template<class t> 
set<t>::set(set<t> &copy) 
{ 
    this->br=copy.br; 
    this->niz=new t[br]; 
    for(int i=0;i<this->br;i++) 
     this->niz[i]=copy.niz[i]; 
} 

movie.h

#include<iostream> 
using namespace std; 

class movie 
{ 
    char* naziv; 
    char* reditelj; 
    int trajanje; 
public: 
    movie(); 
    ~movie(); 
    movie(movie& copy); 
    movie(char* name,char* red,int len); 
    movie& operator=(movie& film); 
    bool operator==(movie& film); 
    friend istream& operator>>(istream& ulaz,movie& film); 
    friend ostream& operator<<(ostream& izlaz,movie& film); 
}; 

movie.cpp

#include"movie.h" 
using namespace std; 

movie::movie() 
{ 
    this->naziv=0; 
    this->reditelj=0; 
    this->trajanje=0; 
} 

movie::~movie() 
{ 
    if(naziv!=0&&reditelj!=0) 
    { 
     delete [] naziv; 
     delete [] reditelj; 
    } 
} 

movie::movie(movie &copy) 
{ 
    this->naziv=new char[strlen(copy.naziv)+1]; 
    strcpy(this->naziv,copy.naziv); 
    this->reditelj=new char[strlen(copy.reditelj)+1]; 
    strcpy(this->reditelj,copy.reditelj); 
    this->trajanje=copy.trajanje; 
} 

movie& movie::operator =(movie &film) 
{ 
    if(this!=&film) 
    { 
     delete [] naziv; 
     delete [] reditelj; 

     this->naziv=new char[strlen(film.naziv)+1]; 
     strcpy(this->naziv,film.naziv); 
     this->reditelj=new char[strlen(film.reditelj)+1]; 
     strcpy(this->reditelj,film.reditelj); 
     this->trajanje=film.trajanje; 
    } 
    return *this; 
} 

bool movie::operator ==(movie &film) 
{ 
    if(!strcmp(this->naziv,film.naziv)&&!strcmp(this->reditelj,film.reditelj)&&this->trajanje==film.trajanje) 
     return true; 
    return false; 
} 

istream& operator>>(istream& ulaz,movie& film) 
{ 
    ulaz>>film.naziv>>film.reditelj>>film.trajanje; 
    return ulaz; 
} 

ostream& operator<<(ostream& izlaz,movie& film) 
{ 
    izlaz<<endl<<film.naziv<<endl<<film.reditelj<<endl<<film.trajanje<<endl; 
    return izlaz; 
} 

movie::movie(char *name, char *red, int len) 
{ 
    this->naziv=new char[strlen(name)+1]; 
    strcpy(naziv,name); 
    this->reditelj=new char[strlen(red)+1]; 
    strcpy(reditelj,red); 
    this->trajanje=len; 
} 
+0

'std :: allocator',可能用'std :: uninitialized_copy'或'std :: uninitialized_fill'。 – 2012-01-04 22:43:03

+2

另外,不要將你的班級命名爲'set',否則你會迷惑每個人。 'std :: set'比你所做的更爲人所知。另外,歡迎來到堆棧溢出。 – 2012-01-04 22:43:55

+1

您是否嘗試使構造函數爲私有?順便說一句。你的問題格式很好:-) – rekire 2012-01-04 22:44:26

回答

1

可以創建對象的數組調用構造函數directl年。

movie objs[2] = {movie(arg1, arg2, arg3), movie(arg1, arg2, arg3)}; 
1

執行此操作的標準方法是使用分配器對象,就像所有標準容器一樣。

template<class T, class alloc_type =std::allocator<T> > 
class set { 
    typedef alloc_type::pointer pointer; //bring in it's pointer type 
    alloc_type alloc; 

然後,使用一切:

pointer buffer = alloc.allocate(100); 
alloc.construct(buffer+0); //deault construct T 
alloc.construct(buffer+1, T()); //construct T from copy 
alloc.construct(buffer+2, 17); //construct T from 17 

alloc.destroy(buffer+2); //clean up objects 
alloc.destroy(buffer+1); 
alloc.destroy(buffer+0); 
alloc.deallocate(buffer); //clean up buffer 

記住,這是標準的構建從最低的指數最高,而在相反的順序給毀了。

這樣做的「正確」方式已經改變了C++ 11,但由於我使用MSVC10,其中不能做正確的方式,我仍然使用這種方式。

雖然這些功能中的每一個的基本實現都很簡單。

template<class T> 
class myallocator { 
public: 
    typedef T value_type; 
    typedef T* pointer; 
    typedef T& reference; 
    typedef const T* const_pointer; 
    typedef const T& const_reference; 
    typedef size_t size_type; 
    typedef ptrdiff_t difference_type; 

    myallocator() throw() {} 
    template <class U> myallocator (const myallocator<U>&) throw() {} 
    pointer address (reference x) const {return &x;} 
    const_pointer address (const_reference x) const {return &x;} 
    size_type max_size() const throw() {return size_type(-1);} 

pointer allocate(size_type c,const_pointer h=0){return(T*)new char[sizeof(T)*c];} 
    void deallocate(pointer ptr, size_type c) {delete [] ptr;} 
    pointer construct(pointer ptr) {return new(ptr)T;} 
    template<class U> 
    pointer construct(pointer ptr, const U& from) {return new(ptr)T(from);} 
    void destroy(pointer ptr) {ptr->~T();} 
}; 

兩個construct成員使用所謂的「新佈局」,這在已經存在的空間創建的對象。這裏是一列char s。

+0

我不知道如何分配器的工作,但我約99.9%確定'T + 0'和所以不正確... – 2012-01-04 22:51:34

+0

哦jeez,'緩存+ 0',而不是'T + 0'。 – 2012-01-04 23:00:27

2

不要使用內置數組,尤其是如果你是新的。內置陣列最好留給專家,即使這樣,他們通常也是最好的避免。而不是使用T[n]只是使用std::vector<T>。這一個將開始清空,然後你可以例如push_back()您感興趣的對象。

這麼說,我沒有看到你的代碼摘錄實際上有一個問題。

0

您正在嘗試編寫自己的容器類,你不應該把它set。我會假設你在這個答案中叫它my_set

我覺得這是你有興趣你希望在這裏默認值傳遞線路:

my_set<t>::my_set(int b, t default_value) 
//creates a my_set with 'b' elements, where each element is set to default_value 

這是您的目標是什麼?如果是這樣,它更容易定義niz作爲*vector<t>,而不是爲t*

template<class t> 
struct my_set { 
    int br; 
    vector<t> *niz; 
    my_set(int b, const t& default_value); 
} 

template<class t> 
my_set<t>::my_set(int b, const t& default_value) { 
//creates a my_set with 'b' elements, where each element is set to 0 
    this->br=b; 
    this->niz=new vector<t>(b, default_value); 
} 

有您可以考慮其他變化,如定義NIZ簡稱爲vector<t>,而不是vector<t>*的,但我認爲這是超出範圍你原來的問題。

最後,我給大家一個我自己的問題。我如何在C++中執行未初始化的數組new[]?我想new已知大小的數組,但與未構造的數據,然後使用類似uninitialized_copy在數據複製。

0

表達new T[n]將永遠爲ňT對象分配空間,並調用T構造在每個元素上。同樣,delete[] niz,將始終在每個元素上調用T析構函數。看來你希望在T構造函數和析構函數被調用,因此而不是使用::operator new[],你可以只使用::operator new及其位置語法手動控制。

你想要niz是一個數組brT對象。取而代之的是:

niz = new T[br]; 

您可以使用此:

niz = static_cast<T *>(::operator new(br * (sizeof (T)))); 

將在堆中分配空間br連續T對象,而不是呼籲任何人的T構造。這基本上就像使用malloc()T對象分配空間。

但是,現在你有一個問題:你如何實際使用T對象之一?之前,你可以用niz[i]做任何事情,你需要確保的是,T對象已建成。您可以使用新的佈局來構建它:

new(niz + i) T(); 

注意niz + i是指針T對象。此聲明的效果是使用reinterpret_cast<char *>(niz + i)reinterpret_cast<char *>(niz + i) + (sizeof (T))的空間調用T構造函數。

現在你還有一個問題:你如何跟蹤哪個對象被構建?你需要知道這個是爲了調用那些已經構造的析構函數,否則你可能會泄漏內存。

一種解決方案是使用具有std::vector<bool>brbool對象。如果booltrue,那麼你就會知道,我T對象構建。否則,它需要構建。

set<T>析構函數,你需要確保摧毀已建成的所有T對象。假設ithT對象已被構建。爲了呼籲T對象,你可以用這個語句T析:

(niz + i)->~T(); 

全部放在一起,你會得到這樣的事情:

#include <cstddef> 
#include <iostream> 
#include <new> 
#include <vector> 

template <typename T> 
class set 
{ 
    std::size_t br; 
    T *niz; 
    std::vector<bool> constructed; 

public: 
    std::string name; 

    set() 
     : br(0), niz(NULL), constructed() 
    { 
    } 

    set(std::size_t br) 
     : br(br), niz(NULL), constructed(br, false) 
    { 
     niz = static_cast<T *>(::operator new(br * (sizeof (T)))); 
    } 

    void destroy() 
    { 
     std::cout << "~set(" << name << ")\n"; 

     if (niz) { 
      std::vector<bool>::const_iterator begin = constructed.begin(), it, end = constructed.end(); 
      for (it = constructed.begin(); it != end; ++it) { 
       if (*it) { 
        (niz + (it - begin))->~T(); 
       } 
      } 
      ::operator delete(niz); 
     } 
    } 

    ~set() 
    { 
     destroy(); 
    } 

    set<T>& operator=(const set<T>& other) 
    { 
     if (this != &other) { 
      destroy(); 
      niz = NULL; 

      constructed = std::vector<bool>(other.br, false); 
      br = other.br; 
      T *tmp = static_cast<T *>(::operator new(other.br * (sizeof (T)))); 
      try { 
       std::size_t i; 
       for (i = 0; i < other.br; ++i) { 
        if (other.constructed[i]) { 
         new(tmp + i) T(other.niz[i]); 
         constructed[i] = true; 
        } 
       } 
      } catch (...) { 
       niz = tmp; 
       destroy(); 
       throw; 
      } 
      niz = tmp; 
      name = other.name + " (2)"; 
     } 
     return *this; 
    } 

    T& operator[](std::size_t i) 
    { 
     if (niz && !constructed[i]) { 
      new(niz + i) T(); 
      constructed[i] = true; 
     } 
     return niz[i]; 
    } 
}; 

struct my_struct 
{ 
    char c; 

    my_struct(char c = 'a') 
     : c(c) 
    { 
     std::cout << "my_struct('" << c << "')\n"; 
    } 

    ~my_struct() 
    { 
     std::cout << "~my_struct('" << c << "')\n"; 
    } 
}; 

int main() 
{ 
    ::set<char> a, a2(3); 
    a.name = "a"; 
    a2.name = "a2"; 

    { 
     ::set<my_struct> b(3); 
     b.name = "b"; 
     b[0].c = '1'; 
     b[2].c = '3'; 
     b[1].c = '2'; 

     ::set<my_struct> b2(4); 
     b2.name = "b2"; 
     b = b2; b.name += ", going by the name 'b'"; 

     b[0].c = 'A'; 
     b2[1].c = 'B'; 
    } 
} 

注意:我不建議實際使用此代碼。關鍵是要了解放置new運算符並通過指針顯式調用析構函數。

有關標準備選方案,請參見STL模板vectorset

0

一個在你的代碼的問題是,如果其中某一字符串爲0

ostream& operator<<(ostream& izlaz,movie& film) 
{ 
    izlaz 
     << endl << film.naziv // fails if film.naziv == 0 
     << endl << film.reditelj // fails if film.reditelj == 0 
     << endl << film.trajanje << endl; 
    return izlaz; 
} 

的崩潰對我來說這將失敗。你不應該這樣做cout << (char*)0;。最好是做一些像cout << ""。你可以通過改變電影的構造方法解決它:

movie::movie() 
{ 
    this->naziv=""; // an empty, non-null, string 
    this->reditelj=""; // an empty, non-null, string 
    this->trajanje=0; 
} 

但更好的方法是停止使用char *,並使用std :: string來代替。

相關問題