2015-10-08 16 views
6

Tất cả các quốc gia có nguồn gốc từ BaseState để biến thành viên mVehicle truy cập các biến lớp ngoài. Tuy nhiên, trong mỗi lớp dẫn xuất, trong tất cả các hàm của mỗi trạng thái, static_cast là cần thiết để truy cập các biến và hàm thành viên lớp dẫn xuất.Biến thành viên lớp dẫn xuất truy cập trong hàm ảo

Bất kỳ giải pháp nào tốt hơn?

  1. Trong mỗi trạng thái của các lớp dẫn xuất, hãy thêm một con trỏ khác (ví dụ: Convertible * mConvertible). Mỗi trạng thái có con trỏ trùng lặp (mConvertible và mVehicle) trỏ đến cùng một đối tượng. Không nhìn đúng.
  2. Sử dụng Getter ảo thay vì mVehicle trong lớp cơ sở. Sẽ có quá nhiều cuộc gọi Getter trong lớp cơ sở.

======================== ===========================

Có. Tôi đã thử mẫu như dưới đây, nhưng không thể biên dịch được vì các lỗi như

"car.h: Trong chức năng thành viên 'khoảng trống ảo :: State1 :: run()': car.h: 18: 12: lỗi : 'mVehicle' không được khai báo trong phạm vi này ".

// car.h 
#include <iostream> 

template <class T> 
class Car { 
public: 
    class BaseState { 
    public: 
     explicit BaseState(T* vehicle) : mVehicle(vehicle) {} 

    protected: 
     T* mVehicle; 
    }; 

    class State1 : public BaseState { 
    public: 
     explicit State1(T* vehicle) : BaseState(vehicle) {} 
     virtual void run() { 
      mVehicle->x = 1; 
      mVehicle->y = 2; 
      mVehicle->doSomething1(); 
      mVehicle->doSomething2(); 
      processEvent(); 
     } 
     virtual void processEvent() { 
      if (mVehicle->val > 2) { 
       std::cout << "too large" << std::endl; 
      } 
     } 
    }; 

    class State2 : public BaseState { 
    public: 
     explicit State2(T* vehicle) : BaseState(vehicle) {} 
     virtual void run() { 
      mVehicle->x = 10; 
      mVehicle->y = 20; 
      processEvent(); 
     } 
     virtual void processEvent() { 
      if (mVehicle->val > 20) { 
       std::cout << "too large" << std::endl; 
      } 
     } 
    }; 

    virtual void doSomething1() { 
     val += x * y; 
    } 

    virtual void doSomething2() { 
     val += x + y; 
    } 

protected: 
    int x; 
    int y; 
    int val; 

}; 

// convertible.h 
#include "car.h" 
#include <iostream> 

class Convertible : public Car<Convertible> { 
protected: 
    class State1 : public Car<Convertible>::State1 { 
     explicit State1(Convertible* vehicle) : Car<Convertible>::State1(vehicle) {} 
     // want to override functions in base class states 
     virtual void processEvent() { 
      if (mVehicle->val > 10) { 
       std::cout << "too large" << std::endl; 
       mVehicle->val = 10; 
      } 
     } 
    }; 

    // want to override some base class functions 
    // and access some special variables 
    // want to inherit other functions 
    virtual void doSomething2() { 
     z = 10; 
     val += x + y + z; 
    } 

protected: 
    int z; 
}; 

Nếu tôi sử dụng State1(Car* vehicle) thay vì State1(T* vehicle), có lỗi chuyển đổi bổ sung. Tôi đang làm gì sai?

Nếu chương trình có thể tìm ra rằng Convertible::State1::processEvent() phải được thực hiện, tại sao nó không thể tự động truyền mVehicle từ Car* đến Convertible*? Rõ ràng là mVehicle trỏ đến một đối tượng Convertible khi số Convertible::State1::processEvent() được suy luận. Chúng tôi không cần mẫu nếu có dàn diễn viên tự động.

+3

Templates. Sử dụng chúng. –

+0

Bạn có thể vui lòng cung cấp thêm thông tin? – dekst

+0

xem câu trả lời. –

Trả lời

1

Việc triển khai này không sử dụng phôi, con trỏ trùng lặp, getters ảo hoặc CRTP.Nó có ba phân cấp song song:

  • xe
  • bang xe trừu tượng mà là giao diện trừu tượng thuần túy
  • bang xe bê tông, nơi nhà nước được tham số hóa bằng cách loại run-loại thực tế của xe.

Vì vậy, chúng tôi có ví dụ:

Car     Car::AbstractState    Car::State<C> 
|      |         | 
+--- Convertible  +--- Convertible::AbstractState +--- Convertible::State<C> 
| |    | |       | | 
| +--- Racer  | +--- Racer::AbstractState | +--- Racer::State<C> 
+--- Hybrid   +--- Hybrid::AbstractState  +--- Hybrid::State<C> 

Mỗi trạng thái cụ thể xuất phát từ và thực hiện trạng thái trừu tượng tương ứng. Nếu chúng tôi có một số Car* trỏ đến một số Convertible và chúng tôi truy vấn trạng thái của nó, chúng tôi nhận được Car::AbstractState* trỏ đến đối tượng trạng thái cụ thể với loại cuối cùng là Convertible::State<Convertible>. Tuy nhiên, người dùng phân cấp ô tô không biết và không quan tâm đến máy móc mẫu.

Mã:

#include <iostream> 
using namespace std; 

struct Trace 
{ 
    Trace(const char* s) : s (s) 
    { 
     cout << s << " start\n"; 
    } 

    ~Trace() 
    { 
     cout << s << " end\n"; 
    } 

    const char* s; 
}; 

struct Car { 
    struct AbstractState 
    { 
     virtual void run() = 0; 
    }; 

    template <typename C> 
    struct State : virtual AbstractState 
    { 
     explicit State(C* vehicle) : mVehicle(vehicle) {} 
     virtual void run() 
     { 
      Trace("Car::State::run"); 
      doSomething(); 
     }; 
     virtual void doSomething() 
     { 
      Trace("Car::State::doSomething"); 
     } 
     C* mVehicle; 
    }; 

    virtual AbstractState* getState() { return new State<Car>(this); } 
}; 


struct Convertible : Car { 

    struct AbstractState : virtual Car::AbstractState 
    { 
     virtual void runBetter() = 0; 
    }; 

    template <typename C> 
    struct State : Car::State<C>, virtual AbstractState 
    { 
     using Car::State<C>::mVehicle; 
     explicit State(C* vehicle) : Car::State<C>(vehicle) {} 
     void doSomething() 
     { 
      Trace("Convertible::State::doSomething"); 
      Car::State<C>::doSomething(); 
      mVehicle->foldTop(); 
     } 

     void runBetter() 
     { 
      Trace("Convertible::State::runBetter"); 
      run(); 
      doSomethingElse(); 
     }; 

     virtual void doSomethingElse() 
     { 
      Trace("Convertible::State::doSomethingElse"); 
     } 
    }; 

    void foldTop() 
    { 
     Trace("Convertible::foldTop"); 
    } 

    Convertible::AbstractState* getState() { return new State<Convertible>(this); } 
}; 

int main() 
{ 
    Car car; 
    Convertible convertible; 
    Car& car2(convertible); 

    cout << "runing car\n"; 
    Car::AbstractState* carstate = car.getState(); 
    carstate->run(); 

    cout << "runing convertible\n"; 
    Convertible::AbstractState* convertiblestate = convertible.getState(); 
    convertiblestate->run(); 

    cout << "runing car2\n"; 
    Car::AbstractState* carstate2 = car2.getState(); 
    carstate2->run(); 
} 
+0

Cảm ơn rất nhiều! Một ví dụ rất tốt cho loại thiết kế này. 'using Car :: State :: mVehicle;' giải quyết vấn đề tôi đang gặp phải. – dekst

3

Sử dụng mẫu.

Xóa con trỏ khỏi Car các lớp bên trong (tạo cho chúng lớp trừu tượng đầy ảo).

Thêm mới lớp mẫu CarT (hoặc suy nghĩ về cái tên hay hơn)

template <typename T> 
class CarT { 

class CarHolder { 
    explicit CarHolder(T* car) : car(car) {} 
    T* car; 
}; 
class State1 : public Car::State1, protected CarHolder { 
    explicit State1(Car* vehicle) : CarHolder(vehicle) {} 
    virtual void run() { 
     // use data of Car 
     ... 
     doSomething(); 
    } 
    virtual void doSomething() { 
    } 
}; 
class State2 : public Car::State2 { 
}; 
... 
}; 

Bằng cách này bạn sẽ có đa hình thời gian chạy của Car và nó State 's và tốt thời gian biên dịch đa hình của các lớp thừa kế (mà lần lượt sẽ loại bỏ nhu cầu xấu xí static_cast)

class Convertible: public CarT<Convertible> { 
    typename CarT<Convertible> Base; 
    class State1 : public Base::State1 { 
     explicit State1(Convertible* vehicle) : Car::State1(vehicle) {} 
     virtual void doSomething() { 
      car->foldTop(); 
     } 
    } 
    class State2 : public Base::State2 { 
    } 
    ... 
    void foldTop() {} 
} 

class Convertible : public CarT<Convertible> có thể trông lạ, nhưng nó sẽ làm việc (CarT sử dụng nó templ tham số ate chỉ là con trỏ, nếu nó đang sử dụng nó như là thành viên giá trị có thể có một số vấn đề)

+0

Cảm ơn! Tôi đã thử một cái gì đó tương tự, nhưng tôi không thể giải quyết lỗi biên dịch. Trong ví dụ của bạn, bạn có nghĩa là 'class State1: public CarHolder {' thay vì 'class State1: public Car :: State1 {'? Dường như có lỗi chuyển đổi từ 'Xe *' sang 'Có thể chuyển đổi *'. – dekst

+0

oh, xấu của tôi, nó nên kế thừa cả hai :) mã cố định – Hcorg

Các vấn đề liên quan