请考虑以下示例:
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void makeSound() {cout << "rawr" << endl;}
};
class Dog : public Animal
{
public:
virtual void makeSound() {cout << "bark" << endl;}
};
int main()
{
Animal animal;
animal.makeSound();
Dog dog;
dog.makeSound();
Animal badDog = Dog();
badDog.makeSound();
Animal* goodDog = new Dog();
goodDog->makeSound();
}
Run Code Online (Sandbox Code Playgroud)
输出是:
rawr
bark
rawr
bark
Run Code Online (Sandbox Code Playgroud)
但我认为产量肯定应该是"粗树皮树皮".badDog有什么用?
更新:您可能对我的另一个问题感兴趣.
我经常在Stack Overflow上阅读这些语句.就个人而言,我没有发现任何问题,除非我以多态方式使用它; 即我必须使用virtual析构函数.
如果我想扩展/添加标准容器的功能那么什么是比继承一个更好的方法?将这些容器包装在自定义类中需要更多的努力并且仍然是不洁净的.
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
virtual int area ()
{ return (0); }
};
class CRectangle: public CPolygon {
public:
int area () { return (width * height); }
};
Run Code Online (Sandbox Code Playgroud)
有汇编警告
Class '[C@1a9e0f7' has virtual method 'area' but non-virtual destructor
Run Code Online (Sandbox Code Playgroud)
如何理解这个警告以及如何改进代码?
[编辑]这个版本现在正确吗?(试图回答用这个概念来阐明自己)
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
virtual ~CPolygon(){};
virtual int area ()
{ return (0); }
};
class CRectangle: public CPolygon {
public: …Run Code Online (Sandbox Code Playgroud) 我有一个嵌套的try-catch代码,如下所示:
void A()
{
try
{
//Code like A = string(NULL) that throws an exception
}
catch(std::exception& ex)
{
cout<<"in A : " << ex.what();
throw ex;
}
}
void B()
{
try
{
A();
}
catch(std::exception& ex)
{
cout<<"in B : " << ex.what();
}
}
Run Code Online (Sandbox Code Playgroud)
运行后我得到了这个结果:
in A: basic_string::_M_construct null not valid
in B: std::exception
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,ex.what()在函数A中正常工作并告诉我正确的描述,但在B中ex.what()告诉我std::exception.为什么会这样?
我在函数A的catch子句中抛出了不同或错误的东西吗?如何抛出嵌套异常以便我可以在B中获得确切的异常描述?
比方说,我有一个类Derived从类派生Base而sizeof(Derived) > sizeof(Base).现在,如果分配一个这样的数组Derived:
Base * myArray = new Derived[42];
Run Code Online (Sandbox Code Playgroud)
然后尝试使用访问n-th对象
doSomethingWithBase(myArray[n]);
Run Code Online (Sandbox Code Playgroud)
然后,由于Base从无效位置访问,这可能(但不总是)导致未定义的行为.
这种编程错误的正确术语是什么?它应该被视为对象切片的情况吗?
我对C++的这种行为感到困惑:
struct A {
virtual void print() const { printf("a\n"); }
};
struct B : public A {
virtual void print() const { printf("b\n"); }
};
struct C {
operator B() { return B(); }
};
void print(const A& a) {
a.print();
}
int main() {
C c;
print(c);
}
Run Code Online (Sandbox Code Playgroud)
那么,测验是,程序的输出是什么 - a或b?嗯,答案是答案.但为什么?
所以我一直在使用从std :: vector派生的容器.也许这是一个糟糕的设计决定,原因有几个,而且你是否应该做这样的事情的问题在这里有广泛的讨论:
我确信我已经错过了一些讨论......但是在链接中找到了两个观点的合理论据.据我所知,"因为~vector()是非虚拟的"是你不应该从stl容器继承的"规则"的基础.但是,如果我在g ++ 4.9.2中查看std :: vector的实现,我发现std :: vector继承自_Vector_base,而_Vector_base是非虚拟析构函数.
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
{
...
~vector() _GLIBCXX_NOEXCEPT
{ std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
_M_get_Tp_allocator()); }
...
}
Run Code Online (Sandbox Code Playgroud)
哪里:
template<typename _Tp, typename _Alloc>
struct _Vector_base
{
...
~_Vector_base() _GLIBCXX_NOEXCEPT
{ _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage
- this->_M_impl._M_start); }
...
}
Run Code Online (Sandbox Code Playgroud)
所以std :: vector的gcc 4.9.2实现继承自带有非虚析构函数的基类.这让我相信这是一种可接受的做法.为什么这样好?这种做法没有危险的具体条件是什么?
我不明白boost :: checked_delete的目的.文件说:
在5.3.5/5中,C++标准允许使用delete-expression删除指向不完整类类型的指针.当类具有非平凡的析构函数或类特定的运算符delete时,行为是未定义的.有些编译器会在删除不完整的类型时发出警告,但不幸的是,并非所有编译器都会发出警告,程序员有时会忽略或禁用警告.
提供的函数和类模板可用于防止这些问题,因为它们需要完整的类型,否则会导致编译错误.
因此,C++标准允许您删除不完整的类型,如果类型具有非平凡的析构函数,则会导致未定义的行为.什么?一个不完整的类型怎么可能有任何析构函数?不完整的类型只是原型吗?
我正在阅读有关非虚拟接口模式的内容:Herb Sutter正在讨论为什么虚拟功能在大多数情况下必须是私有的,在某些情况下受到保护而从不公开.
但在文章的最后他写道:
不要来自具体的课程.或者,正如Scott Meyers在更有效的C++第33项中所述,[8]"使非叶类抽象化".(不可否认,它可能在实践中发生 - 在其他人编写的代码中,当然不是由您自己编写! - 在这种情况下,您可能必须拥有一个公共虚拟析构函数,以适应已经很糟糕的设计.更好地重构但是,如果可以的话,修复设计.)
但我不明白为什么这是一个糟糕的设计
当我们将派生类的对象分配或复制到其基类的对象时,会发生对象切片,从而在该过程中丢失它的派生部分.
这里有更深入的解释:C++中的切片问题是什么?.
(我自己,我不认为它是一个问题,而是语言价值语义的自然结果,但这不是这个问题的重点.)
我想知道的是:有没有你有意使用它的情况?这是一个"工作的正确工具"吗?
c++ ×10
inheritance ×5
polymorphism ×3
arrays ×1
boost ×1
casting ×1
libstdc++ ×1
overloading ×1
standards ×1
terminology ×1
try-catch ×1
vector ×1
virtual ×1