2013-05-21 32 views
7

我在進行iKM測試時遇到了一個問題。有一個基類具有兩個帶私有訪問說明符的抽象方法。有一個派生類覆蓋了這些抽象方法,但使用了protected/public訪問說明符。覆蓋差異訪問規範C++

我從來沒有遇到這樣的事情,派生類中的重寫方法有不同的訪問規範。這是否允許?如果是,它是否符合基礎與派生(即安全可替代)之間的「是」關係。

你能指點我一些可以提供關於類的這些用法的更多細節的參考嗎?

謝謝。

回答

1

許多人指出這是合法的。

但是,「IS-A」部分並不那麼簡單。當涉及到「動態多態性」,「IS-A」關係成立時,也就是說,你可以用超級你做的所有事情,你也可以使用派生實例。然而,在C++中,我們也有一些經常被稱爲靜態多態(靜態多態的模板,大部分時間)。請看下面的例子:

class A { 
public: 
    virtual int m() { 
     return 1; 
    } 
}; 

class B : public A { 
private: 
    virtual int m() { 
     return 2; 
    } 
}; 

template<typename T> 
int fun(T* obj) { 
    return obj->m(); 
} 

現在,當您嘗試使用 「動態多態性」 一切似乎是確定:

A* a = new A(); 
B* b = new B(); 

// dynamic polymorphism 
std::cout << a->m(); // ok 
std::cout << dynamic_cast<A*>(b)->m(); // ok - B instance conforms A interface 
// std::cout << b->m(); fails to compile due to overriden visibility - expected since technically does not violate IS-A relationship 

...但是當你使用「靜態多態」,你可以說,「是一個」關係不再成立:

A* a = new A(); 
B* b = new B(); 

// static polymorphism 
std::cout << fun(a); // ok 
//std::cout << fun(b); // fails to compile - B instance does not conform A interface at compile time 

那麼,到底,不斷變化的方法知名度「而合法」但是這是醜陋的一個C++中的東西可能會導致您陷入陷阱。

1

是的,只要簽名是相同的,這是允許的。 在我看來,是的,你是對的,覆蓋可見性(例如,公共 - >私人)打破IS-A。我相信斯科特·邁爾斯有效的C++系列對此進行了討論。

+0

謝謝你將檢查你指出的參考。謝謝。 – irappa

+0

我不認爲它打破* is-a *,但沒有購買我不知道的書。根據某些人,Scott Meyers可能是[5個最重要的C++人員之一](http://www.artima.com/cppsource/top_cpp_people.html),但他幾乎沒有在線存在。 –

2

允許在兩個方向上(即從privatepublic和從publicprivate)。

另一方面,我認爲它不會打破IS-A關係。我基地我的論點2個事實:

  • 使用Base&(或Base*)處理,你有完全一樣的界面和以前
  • 你可以完美(如果你願意的話)介紹這是一個前進的方法public和調用private方法直接反正:更多的打字
2

有同樣的效果,這是合法的,可訪問靜態(非動態)檢查:

class A { 
public: 
    virtual void foo() = 0; 
private: 
    virtual void bar() = 0; 
}; 

class B : public A { 
private: 
    virtual void foo() {} // public in base, private in derived 
public: 
    virtual void bar() {} // private in base, public in derived 
}; 

void f(A& a, B& b) 
{ 
    a.foo(); // ok 
    b.foo(); // error: B::foo is private 
    a.bar(); // error: A::bar is private 
    b.bar(); // ok (B::bar is public, even though A::bar is private) 
} 

int main() 
{ 
    B b; 
    f(b, b); 
} 

現在,你爲什麼要這麼做?如果直接使用派生類B(第二參數f())而不是通過基礎A接口(f()的第一參數),那麼這很重要。 如果您總是使用摘要A界面(正如我一般推薦的那樣),它仍然符合「IS-A」關係。